Vulkan: Fix depal and shader blending.

This commit is contained in:
Henrik Rydgård 2017-10-31 12:02:10 +01:00
parent 07dfda0633
commit ed2731d197
12 changed files with 76 additions and 72 deletions

View File

@ -127,9 +127,7 @@ VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat
void DepalShaderCacheVulkan::Clear() {
for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) {
// Delete the shader/pipeline too.
vulkan_->Delete().QueueDeletePipeline(shader->second->pipeline);
delete[] shader->second->code;
// Don't need to destroy the pipelines, they're handled by Vulkan2D.
delete shader->second;
}
cache_.clear();

View File

@ -32,13 +32,13 @@ public:
delete[] code;
}
// A Vulkan2D pipeline. Set texture to slot 0 and palette texture to slot 1.
VkPipeline pipeline;
VkPipeline pipeline = VK_NULL_HANDLE;
const char *code = nullptr;;
};
class DepalTextureVulkan {
public:
VulkanTexture *texture;
VulkanTexture *texture = nullptr;
int lastFrame;
};

View File

@ -202,7 +202,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
samp.flags = 0;
samp.magFilter = VK_FILTER_NEAREST;
samp.minFilter = VK_FILTER_NEAREST;
res = vkCreateSampler(device, &samp, nullptr, &depalSampler_);
res = vkCreateSampler(device, &samp, nullptr, &samplerSecondary_);
res = vkCreateSampler(device, &samp, nullptr, &nullSampler_);
assert(VK_SUCCESS == res);
@ -245,8 +245,8 @@ void DrawEngineVulkan::DestroyDeviceObjects() {
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
frame_[i].Destroy(vulkan_);
}
if (depalSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(depalSampler_);
if (samplerSecondary_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(samplerSecondary_);
if (nullSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(nullSampler_);
if (pipelineLayout_ != VK_NULL_HANDLE)
@ -507,12 +507,11 @@ void DrawEngineVulkan::DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset,
}
}
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone) {
DescriptorSetKey key;
key.imageView_ = imageView;
key.sampler_ = sampler;
key.secondaryImageView_ = VK_NULL_HANDLE;
key.secondaryImageView_ = boundSecondary_;
key.base_ = base;
key.light_ = light;
key.bone_ = bone;
@ -561,6 +560,21 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
n++;
}
if (boundSecondary_) {
// TODO: Also support LAYOUT_GENERAL to be able to texture from framebuffers without transitioning them?
tex.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
tex.imageView = boundSecondary_;
tex.sampler = samplerSecondary_;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[n].pNext = nullptr;
writes[n].dstBinding = DRAW_BINDING_2ND_TEXTURE;
writes[n].pImageInfo = &tex;
writes[n].descriptorCount = 1;
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writes[n].dstSet = desc;
n++;
}
// Skipping 2nd texture for now.
// Tessellation data textures
@ -903,7 +917,6 @@ void DrawEngineVulkan::DoFlush() {
const uint32_t dynamicUBOOffsets[3] = {
baseUBOOffset, lightUBOOffset, boneUBOOffset,
};
// vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets);
int stride = dec_->GetDecVtxFmt().stride;

View File

@ -179,6 +179,7 @@ private:
struct FrameData;
void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
void ResetShaderBlending();
void InitDeviceObjects();
void DestroyDeviceObjects();
@ -200,6 +201,10 @@ private:
VulkanPipeline *lastPipeline_;
VkDescriptorSet lastDs_ = VK_NULL_HANDLE;
// Secondary texture for shader blending
VkImageView boundSecondary_ = VK_NULL_HANDLE;
VkSampler samplerSecondary_ = VK_NULL_HANDLE;
PrehashMap<VertexArrayInfoVulkan *, nullptr> vai_;
VulkanPushBuffer *vertexCache_;
int decimationCounter_ = 0;
@ -237,16 +242,14 @@ private:
TextureCacheVulkan *textureCache_ = nullptr;
FramebufferManagerVulkan *framebufferManager_ = nullptr;
VkSampler depalSampler_;
// State cache
uint64_t dirtyUniforms_;
uint32_t baseUBOOffset;
uint32_t lightUBOOffset;
uint32_t boneUBOOffset;
VkBuffer baseBuf, lightBuf, boneBuf;
VkImageView imageView;
VkSampler sampler;
VkImageView imageView = VK_NULL_HANDLE;
VkSampler sampler = VK_NULL_HANDLE;
// Null texture
VulkanTexture *nullTexture_ = nullptr;

View File

@ -337,7 +337,7 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
if ((flags & DRAWTEX_KEEP_TEX) == 0)
overrideImageView_ = VK_NULL_HANDLE;
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
@ -438,10 +438,6 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
}
// Currently rendering to this framebuffer. Need to make a copy.
if (!skipCopy && framebuffer == currentRenderVfb_) {
// ignore this case for now, doesn't work
// ILOG("Texturing from current render Vfb!");
return VK_NULL_HANDLE;
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw::Framebuffer *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (Draw::FBColorDepth)framebuffer->colorDepth);
if (renderCopy) {
@ -453,10 +449,10 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
} else if (framebuffer != currentRenderVfb_) {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
} else {
ERROR_LOG_REPORT_ONCE(vulkanSelfTexture, G3D, "Attempting to texture from target");
// To do this safely in Vulkan, we need to use input attachments.

View File

@ -26,14 +26,12 @@
#include "Core/System.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
//#include "GPU/Vulkan/StateMappingVulkan.h"
#include "GPU/Vulkan/GPU_Vulkan.h"
#include "GPU/Vulkan/PipelineManagerVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/FramebufferVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
//#include "GPU/Vulkan/PixelShaderGeneratorVulkan.h"
// These tables all fit into u8s.
static const VkBlendFactor vkBlendFactorLookup[(size_t)BlendFactor::COUNT] = {
@ -123,8 +121,8 @@ static const VkLogicOp logicOps[] = {
VK_LOGIC_OP_SET,
};
void ResetShaderBlending() {
//
void DrawEngineVulkan::ResetShaderBlending() {
boundSecondary_ = VK_NULL_HANDLE;
}
// TODO: Do this more progressively. No need to compute the entire state if the entire state hasn't changed.
@ -136,8 +134,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
// Unfortunately, this isn't implemented yet.
gstate_c.SetAllowShaderBlend(false);
gstate_c.SetAllowShaderBlend(!g_Config.bDisableSlowFramebufEffects);
if (gstate.isModeClear()) {
key.logicOpEnable = false;
key.logicOp = VK_LOGIC_OP_CLEAR;
@ -375,15 +372,14 @@ void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bo
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
if (!gstate.isModeClear()) {
// TODO: Test texture?
/*
if (fboTexNeedBind_) {
// Note that this is positions, not UVs, that we need the copy from.
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
// If we are rendering at a higher resolution, linear is probably best for the dest color.
boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE1_IMAGEVIEW);
fboTexBound_ = true;
fboTexNeedBind_ = false;
}
*/
}
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {

View File

@ -375,12 +375,11 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
Vulkan2D::Vertex verts[4] = {
{ -1, -1, -1, 0, 0 },
{ 1, -1, -1, 1, 0 },
{ 1, 1, -1, 1, 1 },
{ -1, 1, -1, 0, 1 },
{ -1, -1, 0.0f, 0, 0 },
{ 1, -1, 0.0f, 1, 0 },
{ -1, 1, 0.0f, 0, 1 },
{ 1, 1, 0.0f, 1, 1 },
};
static const int indices[4] = { 0, 1, 3, 2 };
// If min is not < max, then we don't have values (wasn't set during decode.)
if (gstate_c.vertBounds.minV < gstate_c.vertBounds.maxV) {
@ -404,9 +403,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
verts[0].y = bottom;
verts[1].x = right;
verts[1].y = bottom;
verts[2].x = right;
verts[2].x = left;
verts[2].y = top;
verts[3].x = left;
verts[3].x = right;
verts[3].y = top;
// And also the UVs, same order.
@ -418,22 +417,23 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
verts[0].v = uvbottom;
verts[1].u = uvright;
verts[1].v = uvbottom;
verts[2].u = uvright;
verts[2].u = uvleft;
verts[2].v = uvtop;
verts[3].u = uvleft;
verts[3].u = uvright;
verts[3].v = uvtop;
}
VkBuffer pushed;
uint32_t offset = push_->PushAligned(verts, sizeof(verts), 4, &pushed);
ILOG("DEPAL 2");
draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, Draw::FB_COLOR_BIT, 0);
VkImageView fbo = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
VkImageView fbo = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(fbo, samplerNearest_, clutTexture->GetImageView(), samplerNearest_);
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager->BindPipeline(depalShader->pipeline);
renderManager->SetScissor(VkRect2D{ {0, 0}, { framebuffer->renderWidth, framebuffer->renderHeight} });
renderManager->SetViewport(VkViewport{ 0.f, 0.f, (float)framebuffer->renderWidth, (float)framebuffer->renderHeight, 0.f, 1.f });
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, pushed, offset, 4);
shaderManagerVulkan_->DirtyLastShader();
@ -446,7 +446,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
framebufferManager_->RebindFramebuffer();
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0);
imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
// Need to rebind the pipeline since we switched it.
drawEngine_->DirtyPipeline();

View File

@ -56,6 +56,7 @@ public:
void DeviceRestore(VulkanContext *vulkan);
void Shutdown();
// The only supported primitive is the triangle strip, for simplicity.
VkPipeline GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs);
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
void BeginFrame();

View File

@ -303,13 +303,22 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() {
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil) {
// Eliminate dupes.
if (steps_.size() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
if (steps_.size() && steps_.back()->render.framebuffer == fb && steps_.back()->stepType == VKRStepType::RENDER) {
if (color != VKRRenderPassAction::CLEAR && depth != VKRRenderPassAction::CLEAR) {
// We don't move to a new step, this bind was unnecessary.
ILOG("Redundant bind");
// We don't move to a new step, this bind was unnecessary and we can safely skip it.
return;
}
}
if (curRenderStep_ && curRenderStep_->commands.size() == 0 && curRenderStep_->render.color == VKRRenderPassAction::KEEP && curRenderStep_->render.depthStencil == VKRRenderPassAction::KEEP) {
// Can trivially kill the last empty render step.
assert(steps_.back() == curRenderStep_);
delete steps_.back();
steps_.pop_back();
curRenderStep_ = nullptr;
}
if (curRenderStep_ && curRenderStep_->commands.size() == 0) {
ILOG("Empty render step. Usually happens after uploading pixels..");
}
VKRStep *step = new VKRStep{ VKRStepType::RENDER };
// This is what queues up new passes, and can end previous ones.
@ -656,7 +665,6 @@ void VulkanRenderManager::Run(int frame) {
EndSubmitFrame(frame);
VLOG("PULL: Finished running frame %d", frame);
}

View File

@ -226,7 +226,7 @@ private:
int curWidth_;
int curHeight_;
bool insideFrame_ = false;
VKRStep *curRenderStep_;
VKRStep *curRenderStep_ = nullptr;
std::vector<VKRStep *> steps_;
// Execution time state

View File

@ -264,7 +264,8 @@ enum class NativeObject {
BACKBUFFER_RENDERPASS,
FRAMEBUFFER_RENDERPASS,
INIT_COMMANDBUFFER,
BOUND_TEXTURE_IMAGEVIEW,
BOUND_TEXTURE0_IMAGEVIEW,
BOUND_TEXTURE1_IMAGEVIEW,
RENDER_MANAGER,
};

View File

@ -456,9 +456,10 @@ public:
return (uintptr_t)renderManager_.GetCompatibleRenderPass();
case NativeObject::INIT_COMMANDBUFFER:
return (uintptr_t)renderManager_.GetInitCmd();
case NativeObject::BOUND_TEXTURE_IMAGEVIEW:
case NativeObject::BOUND_TEXTURE0_IMAGEVIEW:
return (uintptr_t)boundImageView_[0];
case NativeObject::BOUND_TEXTURE1_IMAGEVIEW:
return (uintptr_t)boundImageView_[1];
case NativeObject::RENDER_MANAGER:
return (uintptr_t)&renderManager_;
default:
@ -480,9 +481,9 @@ private:
VKBuffer *curIBuffer_ = nullptr;
int curIBufferOffset_ = 0;
VkDescriptorSetLayout descriptorSetLayout_;
VkPipelineLayout pipelineLayout_;
VkPipelineCache pipelineCache_;
VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
VKFramebuffer *curFramebuffer_ = nullptr;
VkDevice device_;
@ -490,12 +491,12 @@ private:
int queueFamilyIndex_;
enum {
MAX_BOUND_TEXTURES = 1,
MAX_BOUND_TEXTURES = 2,
MAX_FRAME_COMMAND_BUFFERS = 256,
};
VKTexture *boundTextures_[MAX_BOUND_TEXTURES];
VKSamplerState *boundSamplers_[MAX_BOUND_TEXTURES];
VkImageView boundImageView_[MAX_BOUND_TEXTURES];
VKTexture *boundTextures_[MAX_BOUND_TEXTURES]{};
VKSamplerState *boundSamplers_[MAX_BOUND_TEXTURES]{};
VkImageView boundImageView_[MAX_BOUND_TEXTURES]{};
struct FrameData {
VulkanPushBuffer *pushBuffer;
@ -1291,9 +1292,7 @@ bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits,
VKFramebuffer *src = (VKFramebuffer *)srcfb;
int aspectMask = 0;
if (channelBits & FBChannel::FB_COLOR_BIT) {
aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
}
if (channelBits & FBChannel::FB_COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
@ -1301,20 +1300,11 @@ bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits,
return true;
}
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) {
VKFramebuffer *fb = (VKFramebuffer *)fbo;
VKRRenderPassAction color = (VKRRenderPassAction)rp.color; // same values.
VKRRenderPassAction depth = (VKRRenderPassAction)rp.color; // same values.
if (fb) {
ILOG("Binding image as RT: %x (clear_color: %d)", (int)fb->GetFB()->color.image, rp.color == RPAction::CLEAR);
}
if (fb && boundImageView_[0] == fb->GetFB()->color.imageView) {
// Crash();
}
renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, rp.clearColor, rp.clearDepth, rp.clearStencil);
curFramebuffer_ = fb;
}
@ -1332,9 +1322,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne
if (channelBit & FBChannel::FB_DEPTH_BIT) aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
if (channelBit & FBChannel::FB_STENCIL_BIT) aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
ILOG("Binding image as texture: %x", (int)fb->GetFB()->color.image);
boundImageView_[0] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment);
boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment);
}
uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) {