diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index c54c31cb..4b6cb095 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -960,7 +960,7 @@ bool GraphicPack2::Activate() auto option_upscale = rules.FindOption("upscaleMagFilter"); if(option_upscale && boost::iequals(*option_upscale, "NearestNeighbor")) m_output_settings.upscale_filter = LatteTextureView::MagFilter::kNearestNeighbor; - auto option_downscale = rules.FindOption("NearestNeighbor"); + auto option_downscale = rules.FindOption("downscaleMinFilter"); if (option_downscale && boost::iequals(*option_downscale, "NearestNeighbor")) m_output_settings.downscale_filter = LatteTextureView::MagFilter::kNearestNeighbor; } diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index ca6a2a4d..3bb6c7e3 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -933,13 +933,6 @@ void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPa if (shader == nullptr) { sint32 scaling_filter = downscaling ? GetConfig().downscale_filter : GetConfig().upscale_filter; - - if (g_renderer->GetType() == RendererAPI::Vulkan) - { - // force linear or nearest neighbor filter - if(scaling_filter != kLinearFilter && scaling_filter != kNearestNeighborFilter) - scaling_filter = kLinearFilter; - } if (scaling_filter == kLinearFilter) { @@ -957,7 +950,7 @@ void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPa else shader = RendererOutputShader::s_bicubic_shader; - filter = LatteTextureView::MagFilter::kNearestNeighbor; + filter = LatteTextureView::MagFilter::kLinear; } else if (scaling_filter == kBicubicHermiteFilter) { diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index cf134a5d..bbf988bc 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -570,13 +570,10 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu g_renderer->ClearColorbuffer(padView); } - sint32 effectiveWidth, effectiveHeight; - texView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0); - shader_unbind(RendererShader::ShaderType::kGeometry); shader_bind(shader->GetVertexShader()); shader_bind(shader->GetFragmentShader()); - shader->SetUniformParameters(*texView, { effectiveWidth, effectiveHeight }, { imageWidth, imageHeight }); + shader->SetUniformParameters(*texView, {imageWidth, imageHeight}); // set viewport glViewportIndexedf(0, imageX, imageY, imageWidth, imageHeight); @@ -584,6 +581,12 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu LatteTextureViewGL* texViewGL = (LatteTextureViewGL*)texView; texture_bindAndActivate(texView, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + texViewGL->samplerState.clampS = texViewGL->samplerState.clampT = 0xFF; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, useLinearTexFilter ? GL_LINEAR : GL_NEAREST); + texViewGL->samplerState.filterMin = 0xFFFFFFFF; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, useLinearTexFilter ? GL_LINEAR : GL_NEAREST); texViewGL->samplerState.filterMag = 0xFFFFFFFF; diff --git a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp index cdbeb3f3..409dc24f 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp +++ b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp @@ -2,18 +2,7 @@ #include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h" const std::string RendererOutputShader::s_copy_shader_source = -R"(#version 420 - -#ifdef VULKAN -layout(location = 0) in vec2 passUV; -layout(binding = 0) uniform sampler2D textureSrc; -layout(location = 0) out vec4 colorOut0; -#else -in vec2 passUV; -layout(binding=0) uniform sampler2D textureSrc; -layout(location = 0) out vec4 colorOut0; -#endif - +R"( void main() { colorOut0 = vec4(texture(textureSrc, passUV).rgb,1.0); @@ -22,20 +11,6 @@ void main() const std::string RendererOutputShader::s_bicubic_shader_source = R"( -#version 420 - -#ifdef VULKAN -layout(location = 0) in vec2 passUV; -layout(binding = 0) uniform sampler2D textureSrc; -layout(binding = 1) uniform vec2 textureSrcResolution; -layout(location = 0) out vec4 colorOut0; -#else -in vec2 passUV; -layout(binding=0) uniform sampler2D textureSrc; -uniform vec2 textureSrcResolution; -layout(location = 0) out vec4 colorOut0; -#endif - vec4 cubic(float x) { float x2 = x * x; @@ -48,24 +23,23 @@ vec4 cubic(float x) return w / 6.0; } -vec4 bcFilter(vec2 texcoord, vec2 texscale) +vec4 bcFilter(vec2 uv, vec4 texelSize) { - float fx = fract(texcoord.x); - float fy = fract(texcoord.y); - texcoord.x -= fx; - texcoord.y -= fy; + vec2 pixel = uv*texelSize.zw - 0.5; + vec2 pixelFrac = fract(pixel); + vec2 pixelInt = pixel - pixelFrac; - vec4 xcubic = cubic(fx); - vec4 ycubic = cubic(fy); + vec4 xcubic = cubic(pixelFrac.x); + vec4 ycubic = cubic(pixelFrac.y); - vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y - 0.5, texcoord.y + 1.5); + vec4 c = vec4(pixelInt.x - 0.5, pixelInt.x + 1.5, pixelInt.y - 0.5, pixelInt.y + 1.5); vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x + ycubic.y, ycubic.z + ycubic.w); vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) / s; - vec4 sample0 = texture(textureSrc, vec2(offset.x, offset.z) * texscale); - vec4 sample1 = texture(textureSrc, vec2(offset.y, offset.z) * texscale); - vec4 sample2 = texture(textureSrc, vec2(offset.x, offset.w) * texscale); - vec4 sample3 = texture(textureSrc, vec2(offset.y, offset.w) * texscale); + vec4 sample0 = texture(textureSrc, vec2(offset.x, offset.z) * texelSize.xy); + vec4 sample1 = texture(textureSrc, vec2(offset.y, offset.z) * texelSize.xy); + vec4 sample2 = texture(textureSrc, vec2(offset.x, offset.w) * texelSize.xy); + vec4 sample3 = texture(textureSrc, vec2(offset.y, offset.w) * texelSize.xy); float sx = s.x / (s.x + s.y); float sy = s.z / (s.z + s.w); @@ -76,20 +50,13 @@ vec4 bcFilter(vec2 texcoord, vec2 texscale) } void main(){ - colorOut0 = vec4(bcFilter(passUV*textureSrcResolution, vec2(1.0,1.0)/textureSrcResolution).rgb,1.0); + vec4 texelSize = vec4( 1.0 / textureSrcResolution.xy, textureSrcResolution.xy); + colorOut0 = vec4(bcFilter(passUV, texelSize).rgb,1.0); } )"; const std::string RendererOutputShader::s_hermite_shader_source = -R"(#version 420 - -in vec4 gl_FragCoord; -in vec2 passUV; -layout(binding=0) uniform sampler2D textureSrc; -uniform vec2 textureSrcResolution; -uniform vec2 outputResolution; -layout(location = 0) out vec4 colorOut0; - +R"( // https://www.shadertoy.com/view/MllSzX vec3 CubicHermite (vec3 A, vec3 B, vec3 C, vec3 D, float t) @@ -111,7 +78,7 @@ vec3 BicubicHermiteTexture(vec2 uv, vec4 texelSize) vec2 frac = fract(pixel); pixel = floor(pixel) / texelSize.zw - vec2(texelSize.xy/2.0); - vec4 doubleSize = texelSize*texelSize; + vec4 doubleSize = texelSize*2.0; vec3 C00 = texture(textureSrc, pixel + vec2(-texelSize.x ,-texelSize.y)).rgb; vec3 C10 = texture(textureSrc, pixel + vec2( 0.0 ,-texelSize.y)).rgb; @@ -142,15 +109,17 @@ vec3 BicubicHermiteTexture(vec2 uv, vec4 texelSize) } void main(){ - vec4 texelSize = vec4( 1.0 / outputResolution.xy, outputResolution.xy); + vec4 texelSize = vec4( 1.0 / textureSrcResolution.xy, textureSrcResolution.xy); colorOut0 = vec4(BicubicHermiteTexture(passUV, texelSize), 1.0); } )"; RendererOutputShader::RendererOutputShader(const std::string& vertex_source, const std::string& fragment_source) { + auto finalFragmentSrc = PrependFragmentPreamble(fragment_source); + m_vertex_shader = g_renderer->shader_create(RendererShader::ShaderType::kVertex, 0, 0, vertex_source, false, false); - m_fragment_shader = g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, fragment_source, false, false); + m_fragment_shader = g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, finalFragmentSrc, false, false); m_vertex_shader->PreponeCompilation(true); m_fragment_shader->PreponeCompilation(true); @@ -163,74 +132,45 @@ RendererOutputShader::RendererOutputShader(const std::string& vertex_source, con if (g_renderer->GetType() == RendererAPI::OpenGL) { - m_attributes[0].m_loc_texture_src_resolution = m_vertex_shader->GetUniformLocation("textureSrcResolution"); - m_attributes[0].m_loc_input_resolution = m_vertex_shader->GetUniformLocation("inputResolution"); - m_attributes[0].m_loc_output_resolution = m_vertex_shader->GetUniformLocation("outputResolution"); + m_uniformLocations[0].m_loc_textureSrcResolution = m_vertex_shader->GetUniformLocation("textureSrcResolution"); + m_uniformLocations[0].m_loc_nativeResolution = m_vertex_shader->GetUniformLocation("nativeResolution"); + m_uniformLocations[0].m_loc_outputResolution = m_vertex_shader->GetUniformLocation("outputResolution"); - m_attributes[1].m_loc_texture_src_resolution = m_fragment_shader->GetUniformLocation("textureSrcResolution"); - m_attributes[1].m_loc_input_resolution = m_fragment_shader->GetUniformLocation("inputResolution"); - m_attributes[1].m_loc_output_resolution = m_fragment_shader->GetUniformLocation("outputResolution"); + m_uniformLocations[1].m_loc_textureSrcResolution = m_fragment_shader->GetUniformLocation("textureSrcResolution"); + m_uniformLocations[1].m_loc_nativeResolution = m_fragment_shader->GetUniformLocation("nativeResolution"); + m_uniformLocations[1].m_loc_outputResolution = m_fragment_shader->GetUniformLocation("outputResolution"); } - else - { - cemuLog_logDebug(LogType::Force, "RendererOutputShader() - todo for Vulkan"); - m_attributes[0].m_loc_texture_src_resolution = -1; - m_attributes[0].m_loc_input_resolution = -1; - m_attributes[0].m_loc_output_resolution = -1; - - m_attributes[1].m_loc_texture_src_resolution = -1; - m_attributes[1].m_loc_input_resolution = -1; - m_attributes[1].m_loc_output_resolution = -1; - } - } -void RendererOutputShader::SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& input_res, const Vector2i& output_res) const +void RendererOutputShader::SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& output_res) const { - float res[2]; - // vertex shader - if (m_attributes[0].m_loc_texture_src_resolution != -1) - { - res[0] = (float)texture_view.baseTexture->width; - res[1] = (float)texture_view.baseTexture->height; - m_vertex_shader->SetUniform2fv(m_attributes[0].m_loc_texture_src_resolution, res, 1); - } + sint32 effectiveWidth, effectiveHeight; + texture_view.baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0); + auto setUniforms = [&](RendererShader* shader, const UniformLocations& locations){ + float res[2]; + if (locations.m_loc_textureSrcResolution != -1) + { + res[0] = (float)effectiveWidth; + res[1] = (float)effectiveHeight; + shader->SetUniform2fv(locations.m_loc_textureSrcResolution, res, 1); + } - if (m_attributes[0].m_loc_input_resolution != -1) - { - res[0] = (float)input_res.x; - res[1] = (float)input_res.y; - m_vertex_shader->SetUniform2fv(m_attributes[0].m_loc_input_resolution, res, 1); - } + if (locations.m_loc_nativeResolution != -1) + { + res[0] = (float)texture_view.baseTexture->width; + res[1] = (float)texture_view.baseTexture->height; + shader->SetUniform2fv(locations.m_loc_nativeResolution, res, 1); + } - if (m_attributes[0].m_loc_output_resolution != -1) - { - res[0] = (float)output_res.x; - res[1] = (float)output_res.y; - m_vertex_shader->SetUniform2fv(m_attributes[0].m_loc_output_resolution, res, 1); - } - - // fragment shader - if (m_attributes[1].m_loc_texture_src_resolution != -1) - { - res[0] = (float)texture_view.baseTexture->width; - res[1] = (float)texture_view.baseTexture->height; - m_fragment_shader->SetUniform2fv(m_attributes[1].m_loc_texture_src_resolution, res, 1); - } - - if (m_attributes[1].m_loc_input_resolution != -1) - { - res[0] = (float)input_res.x; - res[1] = (float)input_res.y; - m_fragment_shader->SetUniform2fv(m_attributes[1].m_loc_input_resolution, res, 1); - } - - if (m_attributes[1].m_loc_output_resolution != -1) - { - res[0] = (float)output_res.x; - res[1] = (float)output_res.y; - m_fragment_shader->SetUniform2fv(m_attributes[1].m_loc_output_resolution, res, 1); - } + if (locations.m_loc_outputResolution != -1) + { + res[0] = (float)output_res.x; + res[1] = (float)output_res.y; + shader->SetUniform2fv(locations.m_loc_outputResolution, res, 1); + } + }; + setUniforms(m_vertex_shader, m_uniformLocations[0]); + setUniforms(m_fragment_shader, m_uniformLocations[1]); } RendererOutputShader* RendererOutputShader::s_copy_shader; @@ -341,6 +281,27 @@ void main(){ )"; return vertex_source.str(); } + +std::string RendererOutputShader::PrependFragmentPreamble(const std::string& shaderSrc) +{ + return R"(#version 430 +#ifdef VULKAN +layout(push_constant) uniform pc { + vec2 textureSrcResolution; + vec2 nativeResolution; + vec2 outputResolution; +}; +#else +uniform vec2 textureSrcResolution; +uniform vec2 nativeResolution; +uniform vec2 outputResolution; +#endif + +layout(location = 0) in vec2 passUV; +layout(binding = 0) uniform sampler2D textureSrc; +layout(location = 0) out vec4 colorOut0; +)" + shaderSrc; +} void RendererOutputShader::InitializeStatic() { std::string vertex_source, vertex_source_ud; @@ -349,28 +310,18 @@ void RendererOutputShader::InitializeStatic() { vertex_source = GetOpenGlVertexSource(false); vertex_source_ud = GetOpenGlVertexSource(true); - - s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source); - s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source); - - s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source); - s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source); - - s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source); - s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source); } else { vertex_source = GetVulkanVertexSource(false); vertex_source_ud = GetVulkanVertexSource(true); - - s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source); - s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source); - - /* s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source); TODO - s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source); - - s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source); - s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);*/ } + s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source); + s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source); + + s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source); + s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source); + + s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source); + s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source); } diff --git a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h index 398ac663..61b24c20 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h +++ b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h @@ -17,7 +17,7 @@ public: RendererOutputShader(const std::string& vertex_source, const std::string& fragment_source); virtual ~RendererOutputShader() = default; - void SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& input_res, const Vector2i& output_res) const; + void SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& output_res) const; RendererShader* GetVertexShader() const { @@ -43,16 +43,18 @@ public: static std::string GetVulkanVertexSource(bool render_upside_down); static std::string GetOpenGlVertexSource(bool render_upside_down); + static std::string PrependFragmentPreamble(const std::string& shaderSrc); + protected: RendererShader* m_vertex_shader; RendererShader* m_fragment_shader; - struct + struct UniformLocations { - sint32 m_loc_texture_src_resolution = -1; - sint32 m_loc_input_resolution = -1; - sint32 m_loc_output_resolution = -1; - } m_attributes[2]{}; + sint32 m_loc_textureSrcResolution = -1; + sint32 m_loc_nativeResolution = -1; + sint32 m_loc_outputResolution = -1; + } m_uniformLocations[2]{}; private: static const std::string s_copy_shader_source; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp index f0e2295e..de76f76d 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp @@ -202,6 +202,13 @@ VkSampler LatteTextureViewVk::GetDefaultTextureSampler(bool useLinearTexFilter) VkSamplerCreateInfo samplerInfo{}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + // emulate OpenGL minFilters + // see note under: https://docs.vulkan.org/spec/latest/chapters/samplers.html#VkSamplerCreateInfo + // if maxLod = 0 then magnification is always performed + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.25f; + if (useLinearTexFilter) { samplerInfo.magFilter = VK_FILTER_LINEAR; @@ -212,6 +219,9 @@ VkSampler LatteTextureViewVk::GetDefaultTextureSampler(bool useLinearTexFilter) samplerInfo.magFilter = VK_FILTER_NEAREST; samplerInfo.minFilter = VK_FILTER_NEAREST; } + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; if (vkCreateSampler(m_device, &samplerInfo, nullptr, &sampler) != VK_SUCCESS) { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 9ad2c5ca..37432eeb 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2581,10 +2581,18 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; + VkPushConstantRange pushConstantRange{ + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = 0, + .size = 3 * sizeof(float) * 2 // 3 vec2's + }; + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.pSetLayouts = &descriptorLayout; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; VkResult result = vkCreatePipelineLayout(m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipelineLayout); if (result != VK_SUCCESS) @@ -2956,6 +2964,25 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &descriptSet, 0, nullptr); + // update push constants + Vector2f pushData[3]; + + // textureSrcResolution + sint32 effectiveWidth, effectiveHeight; + texView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0); + pushData[0] = {(float)effectiveWidth, (float)effectiveHeight}; + + // nativeResolution + pushData[1] = { + (float)texViewVk->baseTexture->width, + (float)texViewVk->baseTexture->height, + }; + + // outputResolution + pushData[2] = {(float)imageWidth,(float)imageHeight}; + + vkCmdPushConstants(m_state.currentCommandBuffer, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float) * 2 * 3, &pushData); + vkCmdDraw(m_state.currentCommandBuffer, 6, 1, 0, 0); vkCmdEndRenderPass(m_state.currentCommandBuffer);