diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 37b9dd865d..c2bc891845 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -56,7 +56,7 @@ struct SimpleVertex; class TessellationDataTransfer { public: void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType); - virtual void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) = 0; + virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) = 0; }; class DrawEngineCommon { diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 8f145824af..75866aa11b 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -462,7 +462,7 @@ static void HardwareTessellation(OutputBuffers &output, const Patch &patch, u32 Weight2D weights(WeightType::weightsCache, key_u, key_v); weights.size_u = WeightType::CalcSize(patch.tess_u, patch.count_u); weights.size_v = WeightType::CalcSize(patch.tess_v, patch.count_v); - tessDataTransfer->SendDataToShader(points, patch.count_u * patch.count_v, origVertType, weights); + tessDataTransfer->SendDataToShader(points, patch.count_u, patch.count_v, origVertType, weights); // Generating simple input vertices for the spline-computing vertex shader. float inv_u = 1.0f / (float)patch.tess_u; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index a5c70a34f2..9a90320407 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -702,13 +702,15 @@ TessellationDataTransferD3D11::~TessellationDataTransferD3D11() { } } -void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { struct TessData { float pos[3]; float pad1; float uv[2]; float pad2[2]; float color[4]; }; + int size = size_u * size_v; + if (prevSize < size) { prevSize = size; if (buf[0]) buf[0]->Release(); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index a74dd03458..a29b43553a 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -112,7 +112,7 @@ public: TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device); ~TessellationDataTransferD3D11(); // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; }; // Handles transform, lighting and drawing. diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 4300e18c86..0669412d0a 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -625,7 +625,7 @@ rotateVBO: GPUDebug::NotifyDraw(); } -void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { // TODO } diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 32c0db6e0f..7ec653ddef 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -101,7 +101,7 @@ class TessellationDataTransferDX9 : public TessellationDataTransfer { public: TessellationDataTransferDX9() {} ~TessellationDataTransferDX9() {} - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; }; // Handles transform, lighting and drawing. diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 93ef574b61..79051abb07 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -653,35 +653,36 @@ bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0; + int size = size_u * size_v; float *pos = new float[size * 4]; float *tex = hasTexCoord ? new float[size * 4] : nullptr; float *col = hasColor ? new float[size * 4] : nullptr; int stride = 4; CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType); - // Removed the 1D texture support, it's unlikely to be relevant for performance. // Control Points - if (prevSize < size) { - prevSize = size; + if (prevSizeU < size_u || prevSizeV < size_v) { + prevSizeU = size_u; + prevSizeV = size_v; if (!data_tex[0]) data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); - renderManager_->TextureImage(data_tex[0], 0, size, 3, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); + renderManager_->TextureImage(data_tex[0], 0, size_u * 3, size_v, GL_RGBA32F, GL_RGBA, GL_FLOAT, nullptr, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[0], 0, false); } renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]); // Position - renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size, 1, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW); + renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size_u, size_v, GL_RGBA, GL_FLOAT, (u8 *)pos, GLRAllocType::NEW); // Texcoord if (hasTexCoord) - renderManager_->TextureSubImage(data_tex[0], 0, 0, 1, size, 1, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); + renderManager_->TextureSubImage(data_tex[0], 0, size_u, 0, size_u, size_v, GL_RGBA, GL_FLOAT, (u8 *)tex, GLRAllocType::NEW); // Color if (hasColor) - renderManager_->TextureSubImage(data_tex[0], 0, 0, 2, size, 1, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); + renderManager_->TextureSubImage(data_tex[0], 0, size_u * 2, 0, size_u, size_v, GL_RGBA, GL_FLOAT, (u8 *)col, GLRAllocType::NEW); // Weight U if (prevSizeWU < weights.size_u) { @@ -713,5 +714,5 @@ void TessellationDataTransferGLES::EndFrame() { data_tex[i] = nullptr; } } - prevSize = prevSizeWU = prevSizeWV = 0; + prevSizeU = prevSizeV = prevSizeWU = prevSizeWV = 0; } diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 9870adacd2..858f927485 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -113,7 +113,8 @@ public: class TessellationDataTransferGLES : public TessellationDataTransfer { private: GLRTexture *data_tex[3]{}; - int prevSize = 0, prevSizeWU = 0, prevSizeWV = 0; + int prevSizeU = 0, prevSizeV = 0; + int prevSizeWU = 0, prevSizeWV = 0; GLRenderManager *renderManager_; public: TessellationDataTransferGLES(GLRenderManager *renderManager) @@ -122,7 +123,7 @@ public: EndFrame(); } // Send spline/bezier's control points and weights to vertex shader through floating point texture. - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; void EndFrame(); // Queues textures for deletion. }; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 72b47652f0..926291dc84 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -422,15 +422,16 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " vec3 _pos[16];\n"); WRITE(p, " vec2 _tex[16];\n"); WRITE(p, " vec4 _col[16];\n"); - WRITE(p, " int index;\n"); + WRITE(p, " int index_u, index_v;\n"); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - WRITE(p, " index = (%i + point_pos.y) * u_spline_counts + (%i + point_pos.x);\n", i, j); - WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", i * 4 + j, texelFetch); + WRITE(p, " index_u = (%i + point_pos.x);\n", j); + WRITE(p, " index_v = (%i + point_pos.y);\n", i); + WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, texelFetch); if (doTexture && hasTexcoordTess) - WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", i * 4 + j, texelFetch); + WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, texelFetch); if (hasColorTess) - WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", i * 4 + j, texelFetch); + WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, texelFetch); } } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 0132c57bea..a3bba5d3b7 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -1013,7 +1013,7 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { } } -void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) { +void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) { // SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members // also need to be 16-byte aligned, hence the padding. struct TessData { @@ -1022,6 +1022,8 @@ void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const float color[4]; }; + int size = size_u * size_v; + int ssboAlignment = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minStorageBufferOffsetAlignment; uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), (uint32_t *)&bufInfo_[0].offset, &bufInfo_[0].buffer, ssboAlignment); bufInfo_[0].range = size * sizeof(TessData); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index ad2cb30954..c27e9be04b 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -123,7 +123,7 @@ public: void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. - void SendDataToShader(const SimpleVertex *const *points, int size, u32 vertType, const Weight2D &weights) override; + void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Weight2D &weights) override; const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } private: VulkanContext *vulkan_;