diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 87e400e087..70a8ff0e52 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -45,7 +45,6 @@ FramebufferManagerCommon::FramebufferManagerCommon(Draw::DrawContext *draw) : draw_(draw), displayFormat_(GE_FORMAT_565) { presentation_ = new PresentationCommon(draw); - UpdateSize(); } FramebufferManagerCommon::~FramebufferManagerCommon() { @@ -70,8 +69,8 @@ FramebufferManagerCommon::~FramebufferManagerCommon() { } void FramebufferManagerCommon::Init() { - BeginFrame(); - presentation_->UpdatePostShader(); + // We may need to override the render size if the shader is upscaling or SSAA. + Resized(); } bool FramebufferManagerCommon::UpdateSize() { diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index c8b638f3ce..4df4b43716 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -258,13 +258,10 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha nextHeight = (int)h; } - // No depth/stencil for post processing - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ nextWidth, nextHeight, 1, 1, false, Draw::FBO_8888 }); - if (!fbo) { + if (!AllocateFramebuffer(nextWidth, nextHeight)) { pipeline->Release(); return false; } - postShaderFramebuffers_.push_back(fbo); } postShaderPipelines_.push_back(pipeline); @@ -272,6 +269,31 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha return true; } +bool PresentationCommon::AllocateFramebuffer(int w, int h) { + using namespace Draw; + + // First, let's try to find a framebuffer of the right size that is NOT the most recent. + Framebuffer *last = postShaderFramebuffers_.empty() ? nullptr : postShaderFramebuffers_.back(); + for (const auto &prev : postShaderFBOUsage_) { + if (prev.w == w && prev.h == h && prev.fbo != last) { + // Great, this one's perfect. Ref it for when we release. + prev.fbo->AddRef(); + postShaderFramebuffers_.push_back(prev.fbo); + return true; + } + } + + // No depth/stencil for post processing + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, Draw::FBO_8888 }); + if (!fbo) { + return false; + } + + postShaderFBOUsage_.push_back({ fbo, w, h }); + postShaderFramebuffers_.push_back(fbo); + return true; +} + void PresentationCommon::ShowPostShaderError(const std::string &errorString) { // let's show the first line of the error string as an OSM. std::set blacklistedLines; @@ -406,6 +428,7 @@ void PresentationCommon::DestroyPostShader() { DoReleaseVector(postShaderPipelines_); DoReleaseVector(postShaderFramebuffers_); postShaderInfo_.clear(); + postShaderFBOUsage_.clear(); } Draw::ShaderModule *PresentationCommon::CompileShaderModule(Draw::ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) { @@ -468,11 +491,11 @@ void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidt srcHeight_ = bufferHeight; } -void PresentationCommon::BindSource() { +void PresentationCommon::BindSource(int binding) { if (srcTexture_) { - draw_->BindTexture(0, srcTexture_); + draw_->BindTexture(binding, srcTexture_); } else if (srcFramebuffer_) { - draw_->BindFramebufferAsTexture(srcFramebuffer_, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); } else { assert(false); } @@ -588,8 +611,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (usePostShaderOutput) { draw_->BindFramebufferAsTexture(postShaderFramebuffers_[i - 1], 0, Draw::FB_COLOR_BIT, 0); } else { - BindSource(); + BindSource(0); } + BindSource(1); int nextWidth, nextHeight; draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight); @@ -605,6 +629,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u Draw::SamplerState *sampler = useNearest || shaderInfo->isUpscalingFilter ? samplerNearest_ : samplerLinear_; draw_->BindSamplerStates(0, 1, &sampler); + draw_->BindSamplerStates(1, 1, &sampler); draw_->BindVertexBuffers(0, 1, &vdata_, &postVertsOffset); draw_->BindIndexBuffer(idata_, 0); @@ -635,8 +660,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (usePostShaderOutput) { draw_->BindFramebufferAsTexture(postShaderFramebuffers_.back(), 0, Draw::FB_COLOR_BIT, 0); } else { - BindSource(); + BindSource(0); } + BindSource(1); if (isFinalAtOutputResolution) { PostShaderUniforms uniforms; @@ -653,6 +679,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u Draw::SamplerState *sampler = useNearest ? samplerNearest_ : samplerLinear_; draw_->BindSamplerStates(0, 1, &sampler); + draw_->BindSamplerStates(1, 1, &sampler); auto setViewport = [&](float x, float y, float w, float h) { Draw::Viewport viewport{ x, y, w, h, 0.0f, 1.0f }; diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index eae2834abf..ee0822ea0a 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -112,8 +112,9 @@ protected: Draw::ShaderModule *CompileShaderModule(Draw::ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString); Draw::Pipeline *CreatePipeline(std::vector shaders, bool postShader, const Draw::UniformBufferDesc *uniformDesc); bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next); + bool AllocateFramebuffer(int w, int h); - void BindSource(); + void BindSource(int binding); void GetCardboardSettings(CardboardSettings *cardboardSettings); void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms); @@ -145,4 +146,11 @@ protected: bool usePostShader_ = false; bool restorePostShader_ = false; ShaderLanguage lang_; + + struct PrevFBO { + Draw::Framebuffer *fbo; + int w; + int h; + }; + std::vector postShaderFBOUsage_; }; diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index 192e59f186..2361ba9e11 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -140,6 +140,10 @@ std::string Postprocess(std::string code, ShaderLanguage lang, Draw::ShaderStage out << "sampler2D sampler0 : register(s0);\n"; continue; } + if (line == "uniform sampler2D sampler1;" && lang == HLSL_DX9) { + out << "sampler2D sampler1 : register(s1);\n"; + continue; + } if (line.find("uniform float") != std::string::npos) { continue; } @@ -181,7 +185,10 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada if (line.find("uniform bool") != std::string::npos) { continue; } else if (line.find("uniform sampler2D") == 0) { - line = "layout(set = 0, binding = 1) " + line; + if (line.find("sampler0") != line.npos) + line = "layout(set = 0, binding = 1) " + line; + else + line = "layout(set = 0, binding = 2) " + line; } else if (line.find("uniform ") != std::string::npos) { continue; } else if (2 == sscanf(line.c_str(), "varying vec%d v_texcoord%d;", &vecSize, &num)) { diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 29faefeef3..6e497064c7 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -87,10 +87,10 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngine_.SetShaderManager(shaderManagerD3D11_); drawEngine_.SetTextureCache(textureCacheD3D11_); drawEngine_.SetFramebufferManager(framebufferManagerD3D11_); - framebufferManagerD3D11_->Init(); framebufferManagerD3D11_->SetTextureCache(textureCacheD3D11_); framebufferManagerD3D11_->SetShaderManager(shaderManagerD3D11_); framebufferManagerD3D11_->SetDrawEngine(&drawEngine_); + framebufferManagerD3D11_->Init(); textureCacheD3D11_->SetFramebufferManager(framebufferManagerD3D11_); textureCacheD3D11_->SetDepalShaderCache(depalShaderCache_); textureCacheD3D11_->SetShaderManager(shaderManagerD3D11_); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 1b4aaf857b..6290f14010 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -70,10 +70,10 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngine_.SetShaderManager(shaderManagerDX9_); drawEngine_.SetTextureCache(textureCacheDX9_); drawEngine_.SetFramebufferManager(framebufferManagerDX9_); - framebufferManagerDX9_->Init(); framebufferManagerDX9_->SetTextureCache(textureCacheDX9_); framebufferManagerDX9_->SetShaderManager(shaderManagerDX9_); framebufferManagerDX9_->SetDrawEngine(&drawEngine_); + framebufferManagerDX9_->Init(); textureCacheDX9_->SetFramebufferManager(framebufferManagerDX9_); textureCacheDX9_->SetDepalShaderCache(&depalShaderCache_); textureCacheDX9_->SetShaderManager(shaderManagerDX9_); diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index 5abe33d77c..348411e082 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -21,7 +21,8 @@ #include "Common/Log.h" #include "Common/StringUtils.h" #include "Core/Reporting.h" -#include "DepalettizeShaderGLES.h" +#include "GPU/GLES/DepalettizeShaderGLES.h" +#include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/TextureCacheGLES.h" #include "GPU/Common/DepalettizeShaderCommon.h" @@ -178,8 +179,8 @@ DepalShader *DepalShaderCacheGLES::GetDepalettizeShader(uint32_t clutMode, GEBuf queries.push_back({ &depal->u_pal, "pal" }); std::vector initializer; - initializer.push_back({ &depal->u_tex, 0, 0 }); - initializer.push_back({ &depal->u_pal, 0, 3 }); + initializer.push_back({ &depal->u_tex, 0, TEX_SLOT_PSP_TEXTURE }); + initializer.push_back({ &depal->u_pal, 0, TEX_SLOT_CLUT }); std::vector shaders{ vertexShader_, fragShader }; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 266b4fde93..972b3e9159 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -111,8 +111,6 @@ FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRender void FramebufferManagerGLES::Init() { FramebufferManagerCommon::Init(); - // Workaround for upscaling shaders where we force x1 resolution without saving it - Resized(); CompileDraw2DProgram(); } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 81a53c3dc8..5cf1ec1b41 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -71,10 +71,10 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngine_.SetTextureCache(textureCacheGL_); drawEngine_.SetFramebufferManager(framebufferManagerGL_); drawEngine_.SetFragmentTestCache(&fragmentTestCache_); - framebufferManagerGL_->Init(); framebufferManagerGL_->SetTextureCache(textureCacheGL_); framebufferManagerGL_->SetShaderManager(shaderManagerGL_); framebufferManagerGL_->SetDrawEngine(&drawEngine_); + framebufferManagerGL_->Init(); depalShaderCache_.Init(); textureCacheGL_->SetFramebufferManager(framebufferManagerGL_); textureCacheGL_->SetDepalShaderCache(&depalShaderCache_); diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index dfef7d47b7..2e34182338 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -170,12 +170,6 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo } } -void FramebufferManagerVulkan::Init() { - FramebufferManagerCommon::Init(); - // Workaround for upscaling shaders where we force x1 resolution without saving it - Resized(); -} - void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { float texCoords[8] = { u0,v0, diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index bbd799e1d0..f7da052a50 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -46,8 +46,6 @@ public: // x,y,w,h are relative to destW, destH which fill out the target completely. void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override; - virtual void Init() override; - void BeginFrameVulkan(); // there's a BeginFrame in the base class, which this calls void EndFrame(); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 43de4d1078..d111a1db77 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -72,10 +72,10 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngine_.SetShaderManager(shaderManagerVulkan_); drawEngine_.SetPipelineManager(pipelineManager_); framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_); - framebufferManagerVulkan_->Init(); framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_); framebufferManagerVulkan_->SetDrawEngine(&drawEngine_); framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_); + framebufferManagerVulkan_->Init(); textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_); textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_); textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_); diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 5a297aa974..1406872239 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -926,9 +926,9 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { case GLRRenderCommand::UNIFORMMATRIX: { assert(curProgram); - int loc = c.uniform4.loc ? *c.uniform4.loc : -1; - if (c.uniform4.name) { - loc = curProgram->GetUniformLoc(c.uniform4.name); + int loc = c.uniformMatrix4.loc ? *c.uniformMatrix4.loc : -1; + if (c.uniformMatrix4.name) { + loc = curProgram->GetUniformLoc(c.uniformMatrix4.name); } if (loc >= 0) { glUniformMatrix4fv(loc, 1, false, c.uniformMatrix4.m); diff --git a/ext/native/thin3d/GLQueueRunner.h b/ext/native/thin3d/GLQueueRunner.h index 813f8c020e..e66e346e18 100644 --- a/ext/native/thin3d/GLQueueRunner.h +++ b/ext/native/thin3d/GLQueueRunner.h @@ -117,13 +117,13 @@ struct GLRRenderData { } drawIndexed; struct { const char *name; // if null, use loc - GLint *loc; // NOTE: This is a pointer so we can immediately use things that are "queried" during program creation. + const GLint *loc; // NOTE: This is a pointer so we can immediately use things that are "queried" during program creation. GLint count; float v[4]; } uniform4; struct { const char *name; // if null, use loc - GLint *loc; + const GLint *loc; float m[16]; } uniformMatrix4; struct { diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 377344b073..e579eb7b10 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -630,7 +630,7 @@ public: curRenderStep_->commands.push_back(data); } - void SetUniformI(GLint *loc, int count, const int *udata) { + void SetUniformI(const GLint *loc, int count, const int *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG assert(curProgram_); @@ -642,7 +642,7 @@ public: curRenderStep_->commands.push_back(data); } - void SetUniformI1(GLint *loc, int udata) { + void SetUniformI1(const GLint *loc, int udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG assert(curProgram_); @@ -654,7 +654,7 @@ public: curRenderStep_->commands.push_back(data); } - void SetUniformF(GLint *loc, int count, const float *udata) { + void SetUniformF(const GLint *loc, int count, const float *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG assert(curProgram_); @@ -666,7 +666,7 @@ public: curRenderStep_->commands.push_back(data); } - void SetUniformF1(GLint *loc, const float udata) { + void SetUniformF1(const GLint *loc, const float udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG assert(curProgram_); @@ -690,7 +690,7 @@ public: curRenderStep_->commands.push_back(data); } - void SetUniformM4x4(GLint *loc, const float *udata) { + void SetUniformM4x4(const GLint *loc, const float *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); #ifdef _DEBUG assert(curProgram_); diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index b4d446ed9d..f8531661ba 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -540,7 +540,7 @@ public: void BindTextures(int start, int count, Texture **textures) override; void BindSamplerStates(int start, int count, SamplerState **states) override { for (int i = 0; i < count; ++i) { - D3D9SamplerState *s = static_cast(states[start + i]); + D3D9SamplerState *s = static_cast(states[i]); s->Apply(device_, start + i); } } diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 8eadd95644..f8c6c11a2e 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -323,6 +323,8 @@ public: // TODO: Optimize by getting the locations first and putting in a custom struct UniformBufferDesc dynamicUniforms; + GLint samplerLocs_[8]; + std::vector dynamicUniformLocs_; GLRProgram *program_ = nullptr; private: @@ -387,7 +389,7 @@ public: } for (int i = 0; i < count; i++) { int index = i + start; - boundSamplers_[index] = static_cast(states[index]); + boundSamplers_[index] = static_cast(states[i]); } } @@ -960,6 +962,10 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { return nullptr; } } + if (desc.uniformDesc) { + pipeline->dynamicUniforms = *desc.uniformDesc; + pipeline->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size()); + } ILOG("Linking shaders."); if (pipeline->LinkShaders()) { // Build the rest of the virtual pipeline object. @@ -972,8 +978,6 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { pipeline->blend->AddRef(); pipeline->raster->AddRef(); pipeline->inputLayout->AddRef(); - if (desc.uniformDesc) - pipeline->dynamicUniforms = *desc.uniformDesc; return pipeline; } else { ELOG("Failed to create pipeline - shaders failed to link"); @@ -985,9 +989,9 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { void OpenGLContext::BindTextures(int start, int count, Texture **textures) { maxTextures_ = std::max(maxTextures_, start + count); for (int i = start; i < start + count; i++) { - OpenGLTexture *glTex = static_cast(textures[i]); + OpenGLTexture *glTex = static_cast(textures[i - start]); if (!glTex) { - boundTextures_[i] = 0; + boundTextures_[i] = nullptr; renderManager_.BindTexture(i, nullptr); continue; } @@ -1046,7 +1050,14 @@ bool OpenGLPipeline::LinkShaders() { semantics.push_back({ SEM_POSITION, "a_position" }); semantics.push_back({ SEM_TEXCOORD0, "a_texcoord0" }); std::vector queries; + queries.push_back({ &samplerLocs_[0], "sampler0" }); + queries.push_back({ &samplerLocs_[1], "sampler1" }); + for (size_t i = 0; i < dynamicUniforms.uniforms.size(); ++i) { + queries.push_back({ &dynamicUniformLocs_[i], dynamicUniforms.uniforms[i].name }); + } std::vector initialize; + initialize.push_back({ &samplerLocs_[0], 0, 0 }); + initialize.push_back({ &samplerLocs_[1], 0, 1 }); program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, false); return true; } @@ -1066,17 +1077,19 @@ void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { Crash(); } - for (auto &uniform : curPipeline_->dynamicUniforms.uniforms) { + for (size_t i = 0; i < curPipeline_->dynamicUniforms.uniforms.size(); ++i) { + const auto &uniform = curPipeline_->dynamicUniforms.uniforms[i]; + const GLint &loc = curPipeline_->dynamicUniformLocs_[i]; const float *data = (const float *)((uint8_t *)ub + uniform.offset); switch (uniform.type) { case UniformType::FLOAT1: case UniformType::FLOAT2: case UniformType::FLOAT3: case UniformType::FLOAT4: - renderManager_.SetUniformF(uniform.name, 1 + (int)uniform.type - (int)UniformType::FLOAT1, data); + renderManager_.SetUniformF(&loc, 1 + (int)uniform.type - (int)UniformType::FLOAT1, data); break; case UniformType::MATRIX4X4: - renderManager_.SetUniformM4x4(uniform.name, data); + renderManager_.SetUniformM4x4(&loc, data); break; } } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index c89b079c68..cdcadbea29 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -39,6 +39,7 @@ // We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point. // binding 0 - uniform data // binding 1 - sampler +// binding 2 - sampler // // Vertex data lives in a separate namespace (location = 0, 1, etc) @@ -290,14 +291,20 @@ class VKTexture; class VKBuffer; class VKSamplerState; +enum { + MAX_BOUND_TEXTURES = 2 +}; + struct DescriptorSetKey { - VkImageView imageView_; - VKSamplerState *sampler_; + VkImageView imageViews_[MAX_BOUND_TEXTURES]; + VKSamplerState *samplers_[MAX_BOUND_TEXTURES]; VkBuffer buffer_; bool operator < (const DescriptorSetKey &other) const { - if (imageView_ < other.imageView_) return true; else if (imageView_ > other.imageView_) return false; - if (sampler_ < other.sampler_) return true; else if (sampler_ > other.sampler_) return false; + for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { + if (imageViews_[i] < other.imageViews_[i]) return true; else if (imageViews_[i] > other.imageViews_[i]) return false; + if (samplers_[i] < other.samplers_[i]) return true; else if (samplers_[i] > other.samplers_[i]) return false; + } if (buffer_ < other.buffer_) return true; else if (buffer_ > other.buffer_) return false; return false; } @@ -505,7 +512,6 @@ private: int queueFamilyIndex_; enum { - MAX_BOUND_TEXTURES = 2, MAX_FRAME_COMMAND_BUFFERS = 256, }; VKTexture *boundTextures_[MAX_BOUND_TEXTURES]{}; @@ -669,7 +675,7 @@ RasterState *VKContext::CreateRasterState(const RasterStateDesc &desc) { void VKContext::BindSamplerStates(int start, int count, SamplerState **state) { for (int i = start; i < start + count; i++) { - boundSamplers_[i] = (VKSamplerState *)state[i]; + boundSamplers_[i] = (VKSamplerState *)state[i - start]; } } @@ -790,7 +796,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) VkDescriptorPoolSize dpTypes[2]; dpTypes[0].descriptorCount = 200; dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - dpTypes[1].descriptorCount = 200; + dpTypes[1].descriptorCount = 200 * MAX_BOUND_TEXTURES; dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; @@ -811,21 +817,24 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) } // binding 0 - uniform data - // binding 1 - combined sampler/image - VkDescriptorSetLayoutBinding bindings[2]; + // binding 1 - combined sampler/image 0 + // binding 2 - combined sampler/image 1 + VkDescriptorSetLayoutBinding bindings[MAX_BOUND_TEXTURES + 1]; bindings[0].descriptorCount = 1; bindings[0].pImmutableSamplers = nullptr; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; bindings[0].binding = 0; - bindings[1].descriptorCount = 1; - bindings[1].pImmutableSamplers = nullptr; - bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[1].binding = 1; + for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { + bindings[i + 1].descriptorCount = 1; + bindings[i + 1].pImmutableSamplers = nullptr; + bindings[i + 1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bindings[i + 1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[i + 1].binding = i + 1; + } VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - dsl.bindingCount = 2; + dsl.bindingCount = ARRAY_SIZE(bindings); dsl.pBindings = bindings; VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_); assert(VK_SUCCESS == res); @@ -903,8 +912,10 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { FrameData *frame = &frame_[vulkan_->GetCurFrame()]; - key.imageView_ = boundTextures_[0] ? boundTextures_[0]->GetImageView() : boundImageView_[0]; - key.sampler_ = boundSamplers_[0]; + for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { + key.imageViews_[i] = boundTextures_[i] ? boundTextures_[i]->GetImageView() : boundImageView_[i]; + key.samplers_[i] = boundSamplers_[i]; + } key.buffer_ = buf; auto iter = frame->descSets_.find(key); @@ -927,7 +938,7 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { VkDescriptorImageInfo imageDesc; - VkWriteDescriptorSet writes[2] = {}; + VkWriteDescriptorSet writes[1 + MAX_BOUND_TEXTURES] = {}; // If handles are NULL for whatever buggy reason, it's best to leave the descriptors // unwritten instead of trying to write a zero, which is not legal. @@ -946,24 +957,26 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { numWrites++; } - if (key.imageView_ && boundSamplers_[0] && boundSamplers_[0]->GetSampler()) { - imageDesc.imageView = key.imageView_ ? key.imageView_ : VK_NULL_HANDLE; - imageDesc.sampler = boundSamplers_[0] ? boundSamplers_[0]->GetSampler() : VK_NULL_HANDLE; + for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { + if (key.imageViews_[i] && key.samplers_[i] && key.samplers_[i]->GetSampler()) { + imageDesc.imageView = key.imageViews_[i]; + imageDesc.sampler = key.samplers_[i]->GetSampler(); #ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR - imageDesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageDesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; #else - imageDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; #endif - writes[numWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writes[numWrites].dstSet = descSet; - writes[numWrites].dstArrayElement = 0; - writes[numWrites].dstBinding = 1; - writes[numWrites].pBufferInfo = nullptr; - writes[numWrites].pImageInfo = &imageDesc; - writes[numWrites].pTexelBufferView = nullptr; - writes[numWrites].descriptorCount = 1; - writes[numWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - numWrites++; + writes[numWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[numWrites].dstSet = descSet; + writes[numWrites].dstArrayElement = 0; + writes[numWrites].dstBinding = i + 1; + writes[numWrites].pBufferInfo = nullptr; + writes[numWrites].pImageInfo = &imageDesc; + writes[numWrites].pTexelBufferView = nullptr; + writes[numWrites].descriptorCount = 1; + writes[numWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + numWrites++; + } } vkUpdateDescriptorSets(device_, numWrites, writes, 0, nullptr); @@ -1201,7 +1214,7 @@ void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, void VKContext::BindTextures(int start, int count, Texture **textures) { for (int i = start; i < start + count; i++) { - boundTextures_[i] = static_cast(textures[i]); + boundTextures_[i] = static_cast(textures[i - start]); boundImageView_[i] = boundTextures_[i] ? boundTextures_[i]->GetImageView() : GetNullTexture()->GetImageView(); } }