diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 548d82faef60..1b4751b52748 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 871322073e46..3771d7434473 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -286,13 +286,10 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha nextHeight = (int)rc.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); @@ -300,6 +297,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; @@ -435,6 +457,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) { @@ -497,11 +520,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); } @@ -625,8 +648,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); @@ -642,6 +666,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); @@ -672,8 +697,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; @@ -690,6 +716,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 502ef318e97f..5741c6d79d08 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -122,8 +122,9 @@ class PresentationCommon { 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); @@ -155,4 +156,11 @@ class PresentationCommon { 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 192e59f1860b..2361ba9e1156 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 29faefeef3a9..6e497064c75a 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 d3de79ec2be6..a51db99ca47a 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 5abe33d77c0b..348411e0825d 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 3314068d2447..cd63cb8c0d54 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 ceefecbcb3fd..5635363338da 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 8eead37278f3..0d266d3c9974 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 3a8e1f4304c1..622ad28164a7 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -46,8 +46,6 @@ class FramebufferManagerVulkan : public FramebufferManagerCommon { // 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 43de4d1078b2..d111a1db772f 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 7be3fd09c275..c629c73d9125 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -929,9 +929,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 06ba82af315b..37838f8383fc 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 eac80eac6f81..40cbcb0d2745 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -647,7 +647,7 @@ class GLRenderManager { 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_); @@ -659,7 +659,7 @@ class GLRenderManager { 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_); @@ -671,7 +671,7 @@ class GLRenderManager { 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_); @@ -683,7 +683,7 @@ class GLRenderManager { 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_); @@ -707,7 +707,7 @@ class GLRenderManager { 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 a787bbeef517..d8556210ea5a 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -540,7 +540,7 @@ class D3D9Context : public DrawContext { 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 dd3aa97fb3d7..b168cb02a58a 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -323,6 +323,8 @@ class OpenGLPipeline : public Pipeline { // 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 @@ class OpenGLContext : public DrawContext { } for (int i = 0; i < count; i++) { int index = i + start; - boundSamplers_[index] = static_cast(states[index]); + boundSamplers_[index] = static_cast(states[i]); } } @@ -964,6 +966,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. @@ -976,8 +982,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"); @@ -989,9 +993,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; } @@ -1050,7 +1054,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; } @@ -1070,17 +1081,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 e7f569d7ea29..7bab5391971d 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) @@ -292,14 +293,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; } @@ -512,7 +519,6 @@ class VKContext : public DrawContext { int queueFamilyIndex_; enum { - MAX_BOUND_TEXTURES = 2, MAX_FRAME_COMMAND_BUFFERS = 256, }; VKTexture *boundTextures_[MAX_BOUND_TEXTURES]{}; @@ -676,7 +682,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]; } } @@ -802,7 +808,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 }; @@ -823,21 +829,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); @@ -915,8 +924,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); @@ -937,9 +948,8 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { bufferDesc.offset = 0; bufferDesc.range = curPipeline_->GetUBOSize(); - VkDescriptorImageInfo imageDesc; - - VkWriteDescriptorSet writes[2] = {}; + VkDescriptorImageInfo imageDesc[MAX_BOUND_TEXTURES]{}; + 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. @@ -958,24 +968,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[i].imageView = key.imageViews_[i]; + imageDesc[i].sampler = key.samplers_[i]->GetSampler(); #ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR - imageDesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageDesc[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; #else - imageDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageDesc[i].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[i]; + writes[numWrites].pTexelBufferView = nullptr; + writes[numWrites].descriptorCount = 1; + writes[numWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + numWrites++; + } } vkUpdateDescriptorSets(device_, numWrites, writes, 0, nullptr); @@ -1223,7 +1235,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(); } }