Permalink
Browse files

Vulkan: Fix depal and shader blending.

  • Loading branch information...
hrydgard committed Oct 31, 2017
1 parent 07dfda0 commit ed2731d1978455296258a8a91befb0fcbdac0cfb
@@ -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();
@@ -32,13 +32,13 @@ class DepalShaderVulkan {
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;
};
@@ -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;
@@ -179,6 +179,7 @@ class DrawEngineVulkan : public DrawEngineCommon {
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 @@ class DrawEngineVulkan : public DrawEngineCommon {
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 @@ class DrawEngineVulkan : public DrawEngineCommon {
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;
@@ -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.
@@ -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)) {
@@ -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
@@ -56,6 +56,7 @@ class Vulkan2D {
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();
@@ -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);
}
@@ -226,7 +226,7 @@ class VulkanRenderManager {
int curWidth_;
int curHeight_;
bool insideFrame_ = false;
VKRStep *curRenderStep_;
VKRStep *curRenderStep_ = nullptr;
std::vector<VKRStep *> steps_;
// Execution time state
@@ -264,7 +264,8 @@ enum class NativeObject {
BACKBUFFER_RENDERPASS,
FRAMEBUFFER_RENDERPASS,
INIT_COMMANDBUFFER,
BOUND_TEXTURE_IMAGEVIEW,
BOUND_TEXTURE0_IMAGEVIEW,
BOUND_TEXTURE1_IMAGEVIEW,
RENDER_MANAGER,
};
Oops, something went wrong.

0 comments on commit ed2731d

Please sign in to comment.