mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Renderer: Move cull mode to a rasterization state object
Also moves logic for primitive handling to VideoCommon.
This commit is contained in:
@ -124,15 +124,12 @@ constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128;
|
||||
// Minimum number of draw calls per command buffer when attempting to preempt a readback operation.
|
||||
constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
||||
|
||||
// Rasterization state info
|
||||
union RasterizationState
|
||||
// Multisampling state info that we don't expose in VideoCommon.
|
||||
union MultisamplingState
|
||||
{
|
||||
BitField<0, 2, VkCullModeFlags> cull_mode;
|
||||
BitField<2, 7, VkSampleCountFlagBits> samples;
|
||||
BitField<9, 1, VkBool32> per_sample_shading;
|
||||
BitField<10, 1, VkBool32> depth_clamp;
|
||||
|
||||
u32 bits;
|
||||
BitField<0, 5, u32> samples; // 1-16
|
||||
BitField<0, 1, u32> per_sample_shading; // SSAA
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
// Sampler info
|
||||
|
@ -61,6 +61,39 @@ FramebufferManager* FramebufferManager::GetInstance()
|
||||
return static_cast<FramebufferManager*>(g_framebuffer_manager.get());
|
||||
}
|
||||
|
||||
u32 FramebufferManager::GetEFBWidth() const
|
||||
{
|
||||
return m_efb_color_texture->GetWidth();
|
||||
}
|
||||
|
||||
u32 FramebufferManager::GetEFBHeight() const
|
||||
{
|
||||
return m_efb_color_texture->GetHeight();
|
||||
}
|
||||
|
||||
u32 FramebufferManager::GetEFBLayers() const
|
||||
{
|
||||
return m_efb_color_texture->GetLayers();
|
||||
}
|
||||
|
||||
VkSampleCountFlagBits FramebufferManager::GetEFBSamples() const
|
||||
{
|
||||
return m_efb_color_texture->GetSamples();
|
||||
}
|
||||
|
||||
MultisamplingState FramebufferManager::GetEFBMultisamplingState() const
|
||||
{
|
||||
MultisamplingState ms = {};
|
||||
ms.per_sample_shading = g_ActiveConfig.MultisamplingEnabled() && g_ActiveConfig.bSSAA;
|
||||
ms.samples = static_cast<u32>(GetEFBSamples());
|
||||
return ms;
|
||||
}
|
||||
|
||||
std::pair<u32, u32> FramebufferManager::GetTargetSize() const
|
||||
{
|
||||
return std::make_pair(GetEFBWidth(), GetEFBHeight());
|
||||
}
|
||||
|
||||
bool FramebufferManager::Initialize()
|
||||
{
|
||||
if (!CreateEFBRenderPass())
|
||||
@ -117,22 +150,17 @@ bool FramebufferManager::Initialize()
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<u32, u32> FramebufferManager::GetTargetSize() const
|
||||
{
|
||||
return std::make_pair(m_efb_width, m_efb_height);
|
||||
}
|
||||
|
||||
bool FramebufferManager::CreateEFBRenderPass()
|
||||
{
|
||||
m_efb_samples = static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples);
|
||||
VkSampleCountFlagBits samples = static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples);
|
||||
|
||||
// render pass for rendering to the efb
|
||||
VkAttachmentDescription attachments[] = {
|
||||
{0, EFB_COLOR_TEXTURE_FORMAT, m_efb_samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
{0, EFB_COLOR_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
|
||||
{0, EFB_DEPTH_TEXTURE_FORMAT, m_efb_samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
{0, EFB_DEPTH_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}};
|
||||
@ -177,7 +205,7 @@ bool FramebufferManager::CreateEFBRenderPass()
|
||||
}
|
||||
|
||||
// render pass for resolving depth, since we can't do it with vkCmdResolveImage
|
||||
if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT)
|
||||
if (g_ActiveConfig.MultisamplingEnabled())
|
||||
{
|
||||
VkAttachmentDescription resolve_attachment = {0,
|
||||
EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
||||
@ -228,30 +256,32 @@ void FramebufferManager::DestroyEFBRenderPass()
|
||||
|
||||
bool FramebufferManager::CreateEFBFramebuffer()
|
||||
{
|
||||
m_efb_width = static_cast<u32>(std::max(g_renderer->GetTargetWidth(), 1));
|
||||
m_efb_height = static_cast<u32>(std::max(g_renderer->GetTargetHeight(), 1));
|
||||
m_efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1;
|
||||
INFO_LOG(VIDEO, "EFB size: %ux%ux%u", m_efb_width, m_efb_height, m_efb_layers);
|
||||
u32 efb_width = static_cast<u32>(std::max(g_renderer->GetTargetWidth(), 1));
|
||||
u32 efb_height = static_cast<u32>(std::max(g_renderer->GetTargetHeight(), 1));
|
||||
u32 efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1;
|
||||
VkSampleCountFlagBits efb_samples =
|
||||
static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples);
|
||||
INFO_LOG(VIDEO, "EFB size: %ux%ux%u", efb_width, efb_height, efb_layers);
|
||||
|
||||
// Update the static variable in the base class. Why does this even exist?
|
||||
FramebufferManagerBase::m_EFBLayers = m_efb_layers;
|
||||
FramebufferManagerBase::m_EFBLayers = g_ActiveConfig.iMultisamples;
|
||||
|
||||
// Allocate EFB render targets
|
||||
m_efb_color_texture =
|
||||
Texture2D::Create(m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT,
|
||||
m_efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
|
||||
// We need a second texture to swap with for changing pixel formats
|
||||
m_efb_convert_color_texture =
|
||||
Texture2D::Create(m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT,
|
||||
m_efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
|
||||
m_efb_depth_texture = Texture2D::Create(
|
||||
m_efb_width, m_efb_height, 1, m_efb_layers, EFB_DEPTH_TEXTURE_FORMAT, m_efb_samples,
|
||||
efb_width, efb_height, 1, efb_layers, EFB_DEPTH_TEXTURE_FORMAT, efb_samples,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
@ -260,16 +290,16 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||
return false;
|
||||
|
||||
// Create resolved textures if MSAA is on
|
||||
if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT)
|
||||
if (g_ActiveConfig.MultisamplingEnabled())
|
||||
{
|
||||
m_efb_resolve_color_texture = Texture2D::Create(
|
||||
m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT,
|
||||
efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
|
||||
m_efb_resolve_depth_texture = Texture2D::Create(
|
||||
m_efb_width, m_efb_height, 1, m_efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
||||
efb_width, efb_height, 1, efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
||||
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
@ -284,9 +314,9 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||
m_depth_resolve_render_pass,
|
||||
1,
|
||||
&attachment,
|
||||
m_efb_width,
|
||||
m_efb_height,
|
||||
m_efb_layers};
|
||||
efb_width,
|
||||
efb_height,
|
||||
efb_layers};
|
||||
|
||||
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
||||
&m_depth_resolve_framebuffer);
|
||||
@ -307,9 +337,9 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||
m_efb_load_render_pass,
|
||||
static_cast<u32>(ArraySize(framebuffer_attachments)),
|
||||
framebuffer_attachments,
|
||||
m_efb_width,
|
||||
m_efb_height,
|
||||
m_efb_layers};
|
||||
efb_width,
|
||||
efb_height,
|
||||
efb_layers};
|
||||
|
||||
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
||||
&m_efb_framebuffer);
|
||||
@ -338,8 +368,8 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||
// Clear the contents of the buffers.
|
||||
static const VkClearColorValue clear_color = {{0.0f, 0.0f, 0.0f, 0.0f}};
|
||||
static const VkClearDepthStencilValue clear_depth = {0.0f, 0};
|
||||
VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, m_efb_layers};
|
||||
VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, m_efb_layers};
|
||||
VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, efb_layers};
|
||||
VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, efb_layers};
|
||||
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clear_color, 1, &clear_color_range);
|
||||
@ -438,16 +468,12 @@ void FramebufferManager::ReinterpretPixelData(int convtype)
|
||||
m_efb_load_render_pass, g_shader_cache->GetScreenQuadVertexShader(),
|
||||
g_shader_cache->GetScreenQuadGeometryShader(), pixel_shader);
|
||||
|
||||
RasterizationState rs_state = Util::GetNoCullRasterizationState();
|
||||
rs_state.samples = m_efb_samples;
|
||||
rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE;
|
||||
draw.SetRasterizationState(rs_state);
|
||||
|
||||
VkRect2D region = {{0, 0}, {m_efb_width, m_efb_height}};
|
||||
VkRect2D region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
|
||||
draw.SetMultisamplingState(GetEFBMultisamplingState());
|
||||
draw.BeginRenderPass(m_efb_convert_framebuffer, region);
|
||||
draw.SetPSSampler(0, m_efb_color_texture->GetView(), g_object_cache->GetPointSampler());
|
||||
draw.SetViewportAndScissor(0, 0, m_efb_width, m_efb_height);
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.SetViewportAndScissor(0, 0, GetEFBWidth(), GetEFBHeight());
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
|
||||
// Swap EFB texture pointers
|
||||
@ -458,7 +484,7 @@ void FramebufferManager::ReinterpretPixelData(int convtype)
|
||||
Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||
{
|
||||
// Return the normal EFB texture if multisampling is off.
|
||||
if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT)
|
||||
if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT)
|
||||
return m_efb_color_texture.get();
|
||||
|
||||
// Can't resolve within a render pass.
|
||||
@ -467,8 +493,8 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||
// It's not valid to resolve out-of-bounds coordinates.
|
||||
// Ensuring the region is within the image is the caller's responsibility.
|
||||
_assert_(region.offset.x >= 0 && region.offset.y >= 0 &&
|
||||
(static_cast<u32>(region.offset.x) + region.extent.width) <= m_efb_width &&
|
||||
(static_cast<u32>(region.offset.y) + region.extent.height) <= m_efb_height);
|
||||
(static_cast<u32>(region.offset.x) + region.extent.width) <= GetEFBWidth() &&
|
||||
(static_cast<u32>(region.offset.y) + region.extent.height) <= GetEFBHeight());
|
||||
|
||||
// Resolving is considered to be a transfer operation.
|
||||
m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
@ -478,11 +504,11 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||
|
||||
// Resolve to our already-created texture.
|
||||
VkImageResolve resolve = {
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, m_efb_layers}, // VkImageSubresourceLayers srcSubresource
|
||||
{region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, m_efb_layers}, // VkImageSubresourceLayers dstSubresource
|
||||
{region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset
|
||||
{region.extent.width, region.extent.height, m_efb_layers} // VkExtent3D extent
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers srcSubresource
|
||||
{region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers dstSubresource
|
||||
{region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset
|
||||
{region.extent.width, region.extent.height, GetEFBLayers()} // VkExtent3D extent
|
||||
};
|
||||
vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
@ -498,7 +524,7 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||
Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region)
|
||||
{
|
||||
// Return the normal EFB texture if multisampling is off.
|
||||
if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT)
|
||||
if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT)
|
||||
return m_efb_depth_texture.get();
|
||||
|
||||
// Can't resolve within a render pass.
|
||||
@ -516,7 +542,7 @@ Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region)
|
||||
draw.SetPSSampler(0, m_efb_depth_texture->GetView(), g_object_cache->GetPointSampler());
|
||||
draw.SetViewportAndScissor(region.offset.x, region.offset.y, region.extent.width,
|
||||
region.extent.height);
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
|
||||
// Restore MSAA texture ready for rendering again
|
||||
@ -646,11 +672,11 @@ bool FramebufferManager::CompileConversionShaders()
|
||||
|
||||
m_ps_rgb8_to_rgba6 = Util::CompileAndCreateFragmentShader(header + RGB8_TO_RGBA6_SHADER_SOURCE);
|
||||
m_ps_rgba6_to_rgb8 = Util::CompileAndCreateFragmentShader(header + RGBA6_TO_RGB8_SHADER_SOURCE);
|
||||
if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT)
|
||||
if (GetEFBSamples() != VK_SAMPLE_COUNT_1_BIT)
|
||||
m_ps_depth_resolve = Util::CompileAndCreateFragmentShader(header + DEPTH_RESOLVE_SHADER_SOURCE);
|
||||
|
||||
return (m_ps_rgba6_to_rgb8 != VK_NULL_HANDLE && m_ps_rgb8_to_rgba6 != VK_NULL_HANDLE &&
|
||||
(m_efb_samples == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE));
|
||||
(GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE));
|
||||
}
|
||||
|
||||
void FramebufferManager::DestroyConversionShaders()
|
||||
@ -685,13 +711,13 @@ bool FramebufferManager::PopulateColorReadbackTexture()
|
||||
StateTracker::GetInstance()->OnReadback();
|
||||
|
||||
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
|
||||
VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}};
|
||||
VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
|
||||
Texture2D* src_texture = m_efb_color_texture.get();
|
||||
VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if (m_efb_samples > 1)
|
||||
if (GetEFBSamples() > 1)
|
||||
src_texture = ResolveEFBColorTexture(src_region);
|
||||
|
||||
if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT)
|
||||
if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT)
|
||||
{
|
||||
m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
@ -709,7 +735,7 @@ bool FramebufferManager::PopulateColorReadbackTexture()
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
||||
draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
|
||||
// Restore EFB to color attachment, since we're done with it.
|
||||
@ -765,16 +791,16 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
|
||||
StateTracker::GetInstance()->OnReadback();
|
||||
|
||||
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
|
||||
VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}};
|
||||
VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
|
||||
Texture2D* src_texture = m_efb_depth_texture.get();
|
||||
VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (m_efb_samples > 1)
|
||||
if (GetEFBSamples() > 1)
|
||||
{
|
||||
// EFB depth resolves are written out as color textures
|
||||
src_texture = ResolveEFBDepthTexture(src_region);
|
||||
src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT)
|
||||
if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT)
|
||||
{
|
||||
m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
@ -792,7 +818,7 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
||||
draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
|
||||
// Restore EFB to depth attachment, since we're done with it.
|
||||
@ -905,12 +931,12 @@ bool FramebufferManager::CreateReadbackRenderPasses()
|
||||
g_vulkan_context->GetDeviceLimits().pointSizeRange[0] > 1 ||
|
||||
g_vulkan_context->GetDeviceLimits().pointSizeRange[1] < 16)
|
||||
{
|
||||
m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
||||
m_poke_primitive = PrimitiveType::TriangleStrip;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Points should be okay.
|
||||
m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
m_poke_primitive = PrimitiveType::Points;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1108,29 +1134,28 @@ void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth)
|
||||
void FramebufferManager::CreatePokeVertices(std::vector<EFBPokeVertex>* destination_list, u32 x,
|
||||
u32 y, float z, u32 color)
|
||||
{
|
||||
// Some devices don't support point sizes >1 (e.g. Adreno).
|
||||
if (m_poke_primitive_topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
|
||||
{
|
||||
// generate quad from the single point (clip-space coordinates)
|
||||
float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||
float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||
destination_list->push_back({{x1, y1, z, 1.0f}, color});
|
||||
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
||||
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
||||
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
||||
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
||||
destination_list->push_back({{x2, y2, z, 1.0f}, color});
|
||||
}
|
||||
else
|
||||
if (m_poke_primitive == PrimitiveType::Points)
|
||||
{
|
||||
// GPU will expand the point to a quad.
|
||||
float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||
float point_size = m_efb_width / static_cast<float>(EFB_WIDTH);
|
||||
float point_size = GetEFBWidth() / static_cast<float>(EFB_WIDTH);
|
||||
destination_list->push_back({{cs_x, cs_y, z, point_size}, color});
|
||||
return;
|
||||
}
|
||||
|
||||
// Some devices don't support point sizes >1 (e.g. Adreno).
|
||||
// Generate quad from the single point (clip-space coordinates).
|
||||
float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||
float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||
destination_list->push_back({{x1, y1, z, 1.0f}, color});
|
||||
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
||||
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
||||
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
||||
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
||||
destination_list->push_back({{x2, y2, z, 1.0f}, color});
|
||||
}
|
||||
|
||||
void FramebufferManager::FlushEFBPokes()
|
||||
@ -1159,16 +1184,16 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t
|
||||
pipeline_info.vertex_format = m_poke_vertex_format.get();
|
||||
pipeline_info.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
||||
pipeline_info.vs = m_poke_vertex_shader;
|
||||
pipeline_info.gs = (m_efb_layers > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE;
|
||||
pipeline_info.gs = (GetEFBLayers() > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE;
|
||||
pipeline_info.ps = m_poke_fragment_shader;
|
||||
pipeline_info.render_pass = m_efb_load_render_pass;
|
||||
pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
|
||||
pipeline_info.rasterization_state.samples = m_efb_samples;
|
||||
pipeline_info.rasterization_state.hex = Util::GetNoCullRasterizationState().hex;
|
||||
pipeline_info.rasterization_state.primitive = m_poke_primitive;
|
||||
pipeline_info.multisampling_state.hex = GetEFBMultisamplingState().hex;
|
||||
pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex;
|
||||
pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex;
|
||||
pipeline_info.blend_state.colorupdate = write_color;
|
||||
pipeline_info.blend_state.alphaupdate = write_color;
|
||||
pipeline_info.primitive_topology = m_poke_primitive_topology;
|
||||
if (write_depth)
|
||||
{
|
||||
pipeline_info.depth_state.testenable = true;
|
||||
@ -1209,7 +1234,7 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t
|
||||
StateTracker::GetInstance()->EndClearRenderPass();
|
||||
StateTracker::GetInstance()->BeginRenderPass();
|
||||
StateTracker::GetInstance()->SetPendingRebind();
|
||||
Util::SetViewportAndScissor(command_buffer, 0, 0, m_efb_width, m_efb_height);
|
||||
Util::SetViewportAndScissor(command_buffer, 0, 0, GetEFBWidth(), GetEFBHeight());
|
||||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
vkCmdBindVertexBuffers(command_buffer, 0, 1, &vb_buffer, &vb_offset);
|
||||
vkCmdDraw(command_buffer, static_cast<u32>(vertex_count), 1, 0, 0);
|
||||
@ -1310,7 +1335,7 @@ bool FramebufferManager::CompilePokeShaders()
|
||||
)";
|
||||
|
||||
std::string source = g_shader_cache->GetUtilityShaderHeader();
|
||||
if (m_poke_primitive_topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
|
||||
if (m_poke_primitive == PrimitiveType::Points)
|
||||
source += "#define USE_POINT_SIZE 1\n";
|
||||
source += POKE_VERTEX_SHADER_SOURCE;
|
||||
m_poke_vertex_shader = Util::CompileAndCreateVertexShader(source);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
#include "VideoBackends/Vulkan/TextureCache.h"
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
@ -34,13 +35,14 @@ public:
|
||||
|
||||
VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; }
|
||||
VkRenderPass GetEFBClearRenderPass() const { return m_efb_clear_render_pass; }
|
||||
u32 GetEFBWidth() const { return m_efb_width; }
|
||||
u32 GetEFBHeight() const { return m_efb_height; }
|
||||
u32 GetEFBLayers() const { return m_efb_layers; }
|
||||
VkSampleCountFlagBits GetEFBSamples() const { return m_efb_samples; }
|
||||
Texture2D* GetEFBColorTexture() const { return m_efb_color_texture.get(); }
|
||||
Texture2D* GetEFBDepthTexture() const { return m_efb_depth_texture.get(); }
|
||||
VkFramebuffer GetEFBFramebuffer() const { return m_efb_framebuffer; }
|
||||
u32 GetEFBWidth() const;
|
||||
u32 GetEFBHeight() const;
|
||||
u32 GetEFBLayers() const;
|
||||
VkSampleCountFlagBits GetEFBSamples() const;
|
||||
MultisamplingState GetEFBMultisamplingState() const;
|
||||
std::pair<u32, u32> GetTargetSize() const override;
|
||||
|
||||
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width,
|
||||
@ -124,11 +126,6 @@ private:
|
||||
VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE;
|
||||
VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE;
|
||||
|
||||
u32 m_efb_width = 0;
|
||||
u32 m_efb_height = 0;
|
||||
u32 m_efb_layers = 1;
|
||||
VkSampleCountFlagBits m_efb_samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
std::unique_ptr<Texture2D> m_efb_color_texture;
|
||||
std::unique_ptr<Texture2D> m_efb_convert_color_texture;
|
||||
std::unique_ptr<Texture2D> m_efb_depth_texture;
|
||||
@ -160,7 +157,7 @@ private:
|
||||
std::unique_ptr<StreamBuffer> m_poke_vertex_stream_buffer;
|
||||
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
||||
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
||||
VkPrimitiveTopology m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
PrimitiveType m_poke_primitive = PrimitiveType::TriangleStrip;
|
||||
|
||||
VkRenderPass m_copy_color_render_pass = VK_NULL_HANDLE;
|
||||
VkRenderPass m_copy_depth_render_pass = VK_NULL_HANDLE;
|
||||
|
@ -310,10 +310,10 @@ void RasterFont::PrintMultiLineText(VkRenderPass render_pass, const std::string&
|
||||
|
||||
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
|
||||
render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader);
|
||||
render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader,
|
||||
PrimitiveType::Triangles);
|
||||
|
||||
UtilityShaderVertex* vertices =
|
||||
draw.ReserveVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, text.length() * 6);
|
||||
UtilityShaderVertex* vertices = draw.ReserveVertices(text.length() * 6);
|
||||
size_t num_vertices = 0;
|
||||
if (!vertices)
|
||||
return;
|
||||
|
@ -464,10 +464,6 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
|
||||
depth_state.updateenable = z_enable;
|
||||
depth_state.func = ZMode::ALWAYS;
|
||||
|
||||
RasterizationState rs_state = Util::GetNoCullRasterizationState();
|
||||
rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE;
|
||||
rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples();
|
||||
|
||||
// No need to start a new render pass, but we do need to restore viewport state
|
||||
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD),
|
||||
@ -475,7 +471,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
|
||||
g_shader_cache->GetPassthroughVertexShader(),
|
||||
g_shader_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader);
|
||||
|
||||
draw.SetRasterizationState(rs_state);
|
||||
draw.SetMultisamplingState(FramebufferManager::GetInstance()->GetEFBMultisamplingState());
|
||||
draw.SetDepthState(depth_state);
|
||||
draw.SetBlendState(blend_state);
|
||||
|
||||
@ -1227,13 +1223,8 @@ void Renderer::BindEFBToStateTracker()
|
||||
FramebufferManager::GetInstance()->GetEFBClearRenderPass());
|
||||
StateTracker::GetInstance()->SetFramebuffer(
|
||||
FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size);
|
||||
|
||||
// Update rasterization state with MSAA info
|
||||
RasterizationState rs_state = {};
|
||||
rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits;
|
||||
rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples();
|
||||
rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE;
|
||||
StateTracker::GetInstance()->SetRasterizationState(rs_state);
|
||||
StateTracker::GetInstance()->SetMultisamplingstate(
|
||||
FramebufferManager::GetInstance()->GetEFBMultisamplingState());
|
||||
}
|
||||
|
||||
void Renderer::ResizeEFBTextures()
|
||||
@ -1276,31 +1267,9 @@ void Renderer::RestoreAPIState()
|
||||
StateTracker::GetInstance()->SetPendingRebind();
|
||||
}
|
||||
|
||||
void Renderer::SetGenerationMode()
|
||||
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||
{
|
||||
RasterizationState new_rs_state = {};
|
||||
new_rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits;
|
||||
|
||||
switch (bpmem.genMode.cullmode)
|
||||
{
|
||||
case GenMode::CULL_NONE:
|
||||
new_rs_state.cull_mode = VK_CULL_MODE_NONE;
|
||||
break;
|
||||
case GenMode::CULL_BACK:
|
||||
new_rs_state.cull_mode = VK_CULL_MODE_BACK_BIT;
|
||||
break;
|
||||
case GenMode::CULL_FRONT:
|
||||
new_rs_state.cull_mode = VK_CULL_MODE_FRONT_BIT;
|
||||
break;
|
||||
case GenMode::CULL_ALL:
|
||||
new_rs_state.cull_mode = VK_CULL_MODE_FRONT_AND_BACK;
|
||||
break;
|
||||
default:
|
||||
new_rs_state.cull_mode = VK_CULL_MODE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
StateTracker::GetInstance()->SetRasterizationState(new_rs_state);
|
||||
StateTracker::GetInstance()->SetRasterizationState(state);
|
||||
}
|
||||
|
||||
void Renderer::SetDepthState(const DepthState& state)
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
|
||||
void SetBlendingState(const BlendingState& state) override;
|
||||
void SetScissorRect(const EFBRectangle& rc) override;
|
||||
void SetGenerationMode() override;
|
||||
void SetRasterizationState(const RasterizationState& state) override;
|
||||
void SetDepthState(const DepthState& state) override;
|
||||
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
|
||||
void SetInterlacingMode() override;
|
||||
|
@ -89,36 +89,43 @@ static bool IsStripPrimitiveTopology(VkPrimitiveTopology topology)
|
||||
static VkPipelineRasterizationStateCreateInfo
|
||||
GetVulkanRasterizationState(const RasterizationState& state)
|
||||
{
|
||||
static constexpr std::array<VkCullModeFlags, 4> cull_modes = {
|
||||
{VK_CULL_MODE_NONE, VK_CULL_MODE_BACK_BIT, VK_CULL_MODE_FRONT_BIT,
|
||||
VK_CULL_MODE_FRONT_AND_BACK}};
|
||||
|
||||
bool depth_clamp = g_ActiveConfig.backend_info.bSupportsDepthClamp;
|
||||
|
||||
return {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineRasterizationStateCreateFlags flags
|
||||
state.depth_clamp, // VkBool32 depthClampEnable
|
||||
VK_FALSE, // VkBool32 rasterizerDiscardEnable
|
||||
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
|
||||
state.cull_mode, // VkCullModeFlags cullMode
|
||||
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
|
||||
VK_FALSE, // VkBool32 depthBiasEnable
|
||||
0.0f, // float depthBiasConstantFactor
|
||||
0.0f, // float depthBiasClamp
|
||||
0.0f, // float depthBiasSlopeFactor
|
||||
1.0f // float lineWidth
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineRasterizationStateCreateFlags flags
|
||||
depth_clamp, // VkBool32 depthClampEnable
|
||||
VK_FALSE, // VkBool32 rasterizerDiscardEnable
|
||||
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
|
||||
cull_modes[state.cullmode], // VkCullModeFlags cullMode
|
||||
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
|
||||
VK_FALSE, // VkBool32 depthBiasEnable
|
||||
0.0f, // float depthBiasConstantFactor
|
||||
0.0f, // float depthBiasClamp
|
||||
0.0f, // float depthBiasSlopeFactor
|
||||
1.0f // float lineWidth
|
||||
};
|
||||
}
|
||||
|
||||
static VkPipelineMultisampleStateCreateInfo
|
||||
GetVulkanMultisampleState(const RasterizationState& rs_state)
|
||||
GetVulkanMultisampleState(const MultisamplingState& state)
|
||||
{
|
||||
return {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineMultisampleStateCreateFlags flags
|
||||
rs_state.samples, // VkSampleCountFlagBits rasterizationSamples
|
||||
rs_state.per_sample_shading, // VkBool32 sampleShadingEnable
|
||||
1.0f, // float minSampleShading
|
||||
nullptr, // const VkSampleMask* pSampleMask;
|
||||
VK_FALSE, // VkBool32 alphaToCoverageEnable
|
||||
VK_FALSE // VkBool32 alphaToOneEnable
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineMultisampleStateCreateFlags flags
|
||||
static_cast<VkSampleCountFlagBits>(
|
||||
state.samples.Value()), // VkSampleCountFlagBits rasterizationSamples
|
||||
state.per_sample_shading, // VkBool32 sampleShadingEnable
|
||||
1.0f, // float minSampleShading
|
||||
nullptr, // const VkSampleMask* pSampleMask;
|
||||
VK_FALSE, // VkBool32 alphaToCoverageEnable
|
||||
VK_FALSE // VkBool32 alphaToOneEnable
|
||||
};
|
||||
}
|
||||
|
||||
@ -261,13 +268,13 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info)
|
||||
info.vertex_format ? info.vertex_format->GetVertexInputStateInfo() : empty_vertex_input_state;
|
||||
|
||||
// Input assembly
|
||||
static constexpr std::array<VkPrimitiveTopology, 4> vk_primitive_topologies = {
|
||||
{VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}};
|
||||
VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineInputAssemblyStateCreateFlags flags
|
||||
info.primitive_topology, // VkPrimitiveTopology topology
|
||||
VK_FALSE // VkBool32 primitiveRestartEnable
|
||||
};
|
||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0,
|
||||
vk_primitive_topologies[static_cast<u32>(info.rasterization_state.primitive.Value())],
|
||||
VK_FALSE};
|
||||
|
||||
// See Vulkan spec, section 19:
|
||||
// If topology is VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||
@ -275,7 +282,7 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info)
|
||||
// VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY or VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
|
||||
// primitiveRestartEnable must be VK_FALSE
|
||||
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart &&
|
||||
IsStripPrimitiveTopology(info.primitive_topology))
|
||||
IsStripPrimitiveTopology(input_assembly_state.topology))
|
||||
{
|
||||
input_assembly_state.primitiveRestartEnable = VK_TRUE;
|
||||
}
|
||||
@ -315,9 +322,9 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info)
|
||||
VkPipelineRasterizationStateCreateInfo rasterization_state =
|
||||
GetVulkanRasterizationState(info.rasterization_state);
|
||||
VkPipelineMultisampleStateCreateInfo multisample_state =
|
||||
GetVulkanMultisampleState(info.rasterization_state);
|
||||
GetVulkanMultisampleState(info.multisampling_state);
|
||||
VkPipelineDepthStencilStateCreateInfo depth_stencil_state =
|
||||
GetVulkanDepthStencilState(info.depth_stencil_state);
|
||||
GetVulkanDepthStencilState(info.depth_state);
|
||||
VkPipelineColorBlendAttachmentState blend_attachment_state =
|
||||
GetVulkanAttachmentBlendState(info.blend_state);
|
||||
VkPipelineColorBlendStateCreateInfo blend_state =
|
||||
@ -1203,23 +1210,11 @@ void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid,
|
||||
VK_NULL_HANDLE;
|
||||
pinfo.ps = GetPixelUberShaderForUid(puid);
|
||||
pinfo.render_pass = FramebufferManager::GetInstance()->GetEFBLoadRenderPass();
|
||||
pinfo.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
|
||||
pinfo.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits;
|
||||
pinfo.rasterization_state.hex = Util::GetNoCullRasterizationState().hex;
|
||||
pinfo.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex;
|
||||
pinfo.blend_state.hex = Util::GetNoBlendingBlendState().hex;
|
||||
switch (guid.GetUidData()->primitive_type)
|
||||
{
|
||||
case PRIMITIVE_POINTS:
|
||||
pinfo.primitive_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
break;
|
||||
case PRIMITIVE_LINES:
|
||||
pinfo.primitive_topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||
break;
|
||||
case PRIMITIVE_TRIANGLES:
|
||||
pinfo.primitive_topology = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
break;
|
||||
}
|
||||
pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex;
|
||||
pinfo.rasterization_state.primitive = guid.GetUidData()->primitive_type;
|
||||
GetPipelineWithCacheResultAsync(pinfo);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ struct PipelineInfo
|
||||
BlendingState blend_state;
|
||||
RasterizationState rasterization_state;
|
||||
DepthState depth_state;
|
||||
VkPrimitiveTopology primitive_topology;
|
||||
MultisamplingState multisampling_state;
|
||||
};
|
||||
|
||||
struct PipelineInfoHash
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
#include "VideoBackends/Vulkan/FramebufferManager.h"
|
||||
#include "VideoBackends/Vulkan/ObjectCache.h"
|
||||
#include "VideoBackends/Vulkan/ShaderCache.h"
|
||||
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||
@ -54,26 +53,6 @@ void StateTracker::DestroyInstance()
|
||||
|
||||
bool StateTracker::Initialize()
|
||||
{
|
||||
// Set some sensible defaults
|
||||
m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE;
|
||||
m_pipeline_state.rasterization_state.per_sample_shading = VK_FALSE;
|
||||
m_pipeline_state.rasterization_state.depth_clamp = VK_FALSE;
|
||||
m_pipeline_state.depth_state.testenable = true;
|
||||
m_pipeline_state.depth_state.updateenable = true;
|
||||
m_pipeline_state.depth_state.func = ZMode::ALWAYS;
|
||||
m_pipeline_state.blend_state.hex = 0;
|
||||
m_pipeline_state.blend_state.blendenable = false;
|
||||
m_pipeline_state.blend_state.srcfactor = BlendMode::ONE;
|
||||
m_pipeline_state.blend_state.srcfactoralpha = BlendMode::ONE;
|
||||
m_pipeline_state.blend_state.dstfactor = BlendMode::ZERO;
|
||||
m_pipeline_state.blend_state.dstfactoralpha = BlendMode::ZERO;
|
||||
m_pipeline_state.blend_state.colorupdate = true;
|
||||
m_pipeline_state.blend_state.alphaupdate = true;
|
||||
|
||||
// Enable depth clamping if supported by driver.
|
||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
||||
m_pipeline_state.rasterization_state.depth_clamp = VK_TRUE;
|
||||
|
||||
// BBox is disabled by default.
|
||||
m_pipeline_state.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
||||
m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS;
|
||||
@ -166,13 +145,12 @@ void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info)
|
||||
{
|
||||
SerializedPipelineUID sinfo;
|
||||
sinfo.blend_state_bits = info.blend_state.hex;
|
||||
sinfo.rasterizer_state_bits = info.rasterization_state.bits;
|
||||
sinfo.rasterizer_state_bits = info.rasterization_state.hex;
|
||||
sinfo.depth_state_bits = info.depth_state.hex;
|
||||
sinfo.vertex_decl = m_pipeline_state.vertex_format->GetVertexDeclaration();
|
||||
sinfo.vs_uid = m_vs_uid;
|
||||
sinfo.gs_uid = m_gs_uid;
|
||||
sinfo.ps_uid = m_ps_uid;
|
||||
sinfo.primitive_topology = info.primitive_topology;
|
||||
|
||||
u32 dummy_value = 0;
|
||||
m_uid_cache.Append(sinfo, &dummy_value, 1);
|
||||
@ -211,10 +189,10 @@ bool StateTracker::PrecachePipelineUID(const SerializedPipelineUID& uid)
|
||||
return false;
|
||||
}
|
||||
pinfo.render_pass = m_load_render_pass;
|
||||
pinfo.rasterization_state.bits = uid.rasterizer_state_bits;
|
||||
pinfo.rasterization_state.hex = uid.rasterizer_state_bits;
|
||||
pinfo.depth_state.hex = uid.depth_state_bits;
|
||||
pinfo.blend_state.hex = uid.blend_state_bits;
|
||||
pinfo.primitive_topology = uid.primitive_topology;
|
||||
pinfo.multisampling_state.hex = m_pipeline_state.multisampling_state.hex;
|
||||
|
||||
if (g_ActiveConfig.bBackgroundShaderCompiling)
|
||||
{
|
||||
@ -289,30 +267,21 @@ void StateTracker::SetVertexFormat(const VertexFormat* vertex_format)
|
||||
UpdatePipelineVertexFormat();
|
||||
}
|
||||
|
||||
void StateTracker::SetPrimitiveTopology(VkPrimitiveTopology primitive_topology)
|
||||
{
|
||||
if (m_pipeline_state.primitive_topology == primitive_topology)
|
||||
return;
|
||||
|
||||
m_pipeline_state.primitive_topology = primitive_topology;
|
||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||
}
|
||||
|
||||
void StateTracker::DisableBackFaceCulling()
|
||||
{
|
||||
if (m_pipeline_state.rasterization_state.cull_mode == VK_CULL_MODE_NONE)
|
||||
return;
|
||||
|
||||
m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE;
|
||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||
}
|
||||
|
||||
void StateTracker::SetRasterizationState(const RasterizationState& state)
|
||||
{
|
||||
if (m_pipeline_state.rasterization_state.bits == state.bits)
|
||||
if (m_pipeline_state.rasterization_state.hex == state.hex)
|
||||
return;
|
||||
|
||||
m_pipeline_state.rasterization_state.bits = state.bits;
|
||||
m_pipeline_state.rasterization_state.hex = state.hex;
|
||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||
}
|
||||
|
||||
void StateTracker::SetMultisamplingstate(const MultisamplingState& state)
|
||||
{
|
||||
if (m_pipeline_state.multisampling_state.hex == state.hex)
|
||||
return;
|
||||
|
||||
m_pipeline_state.multisampling_state.hex = state.hex;
|
||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||
}
|
||||
|
||||
@ -334,7 +303,7 @@ void StateTracker::SetBlendState(const BlendingState& state)
|
||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||
}
|
||||
|
||||
bool StateTracker::CheckForShaderChanges(u32 gx_primitive_type)
|
||||
bool StateTracker::CheckForShaderChanges()
|
||||
{
|
||||
VertexShaderUid vs_uid = GetVertexShaderUid();
|
||||
PixelShaderUid ps_uid = GetPixelShaderUid();
|
||||
@ -418,7 +387,7 @@ bool StateTracker::CheckForShaderChanges(u32 gx_primitive_type)
|
||||
|
||||
if (g_vulkan_context->SupportsGeometryShaders())
|
||||
{
|
||||
GeometryShaderUid gs_uid = GetGeometryShaderUid(gx_primitive_type);
|
||||
GeometryShaderUid gs_uid = GetGeometryShaderUid(m_pipeline_state.rasterization_state.primitive);
|
||||
if (gs_uid != m_gs_uid)
|
||||
{
|
||||
m_gs_uid = gs_uid;
|
||||
|
@ -45,20 +45,15 @@ public:
|
||||
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
||||
|
||||
void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass);
|
||||
|
||||
void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area);
|
||||
|
||||
void SetVertexFormat(const VertexFormat* vertex_format);
|
||||
|
||||
void SetPrimitiveTopology(VkPrimitiveTopology primitive_topology);
|
||||
|
||||
void DisableBackFaceCulling();
|
||||
|
||||
void SetRasterizationState(const RasterizationState& state);
|
||||
void SetMultisamplingstate(const MultisamplingState& state);
|
||||
void SetDepthState(const DepthState& state);
|
||||
void SetBlendState(const BlendingState& state);
|
||||
|
||||
bool CheckForShaderChanges(u32 gx_primitive_type);
|
||||
bool CheckForShaderChanges();
|
||||
void ClearShaders();
|
||||
|
||||
void UpdateVertexShaderConstants();
|
||||
@ -133,7 +128,6 @@ private:
|
||||
VertexShaderUid vs_uid;
|
||||
GeometryShaderUid gs_uid;
|
||||
PixelShaderUid ps_uid;
|
||||
VkPrimitiveTopology primitive_topology;
|
||||
};
|
||||
|
||||
// Number of descriptor sets for game draws.
|
||||
|
@ -214,7 +214,7 @@ void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry,
|
||||
g_object_cache->GetPointSampler());
|
||||
draw.SetPSTexelBuffer(m_texel_buffer_view_r16_uint);
|
||||
draw.SetViewportAndScissor(0, 0, dst_entry->GetWidth(), dst_entry->GetHeight());
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
|
||||
|
||||
VkRect2D render_region = {{0, 0}, {render_width, render_height}};
|
||||
draw.BeginRenderPass(m_encoding_render_framebuffer, render_region);
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
|
||||
// Transition the image before copying
|
||||
@ -382,7 +382,7 @@ void TextureConverter::DecodeYUYVTextureFromMemory(VKTexture* dst_texture, const
|
||||
draw.SetViewportAndScissor(0, 0, static_cast<int>(src_width), static_cast<int>(src_height));
|
||||
draw.SetPSTexelBuffer(m_texel_buffer_view_rgba8_unorm);
|
||||
draw.SetPushConstants(&push_constants, sizeof(push_constants));
|
||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||
draw.DrawWithoutVertexBuffer(4);
|
||||
draw.EndRenderPass();
|
||||
}
|
||||
|
||||
|
@ -188,10 +188,7 @@ VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor)
|
||||
RasterizationState GetNoCullRasterizationState()
|
||||
{
|
||||
RasterizationState state = {};
|
||||
state.cull_mode = VK_CULL_MODE_NONE;
|
||||
state.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
state.per_sample_shading = VK_FALSE;
|
||||
state.depth_clamp = VK_FALSE;
|
||||
state.cullmode = GenMode::CULL_NONE;
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -335,7 +332,7 @@ VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, boo
|
||||
UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer,
|
||||
VkPipelineLayout pipeline_layout, VkRenderPass render_pass,
|
||||
VkShaderModule vertex_shader, VkShaderModule geometry_shader,
|
||||
VkShaderModule pixel_shader)
|
||||
VkShaderModule pixel_shader, PrimitiveType primitive)
|
||||
: m_command_buffer(command_buffer)
|
||||
{
|
||||
// Populate minimal pipeline state
|
||||
@ -345,16 +342,16 @@ UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer,
|
||||
m_pipeline_info.vs = vertex_shader;
|
||||
m_pipeline_info.gs = geometry_shader;
|
||||
m_pipeline_info.ps = pixel_shader;
|
||||
m_pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
|
||||
m_pipeline_info.rasterization_state.hex = Util::GetNoCullRasterizationState().hex;
|
||||
m_pipeline_info.rasterization_state.primitive = primitive;
|
||||
m_pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex;
|
||||
m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex;
|
||||
m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
m_pipeline_info.multisampling_state.per_sample_shading = false;
|
||||
m_pipeline_info.multisampling_state.samples = 1;
|
||||
}
|
||||
|
||||
UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(VkPrimitiveTopology topology, size_t count)
|
||||
UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(size_t count)
|
||||
{
|
||||
m_pipeline_info.primitive_topology = topology;
|
||||
|
||||
if (!g_object_cache->GetUtilityShaderVertexBuffer()->ReserveMemory(
|
||||
sizeof(UtilityShaderVertex) * count, sizeof(UtilityShaderVertex), true, true, true))
|
||||
PanicAlert("Failed to allocate space for vertices in backend shader");
|
||||
@ -372,10 +369,9 @@ void UtilityShaderDraw::CommitVertices(size_t count)
|
||||
m_vertex_count = static_cast<uint32_t>(count);
|
||||
}
|
||||
|
||||
void UtilityShaderDraw::UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices,
|
||||
size_t count)
|
||||
void UtilityShaderDraw::UploadVertices(UtilityShaderVertex* vertices, size_t count)
|
||||
{
|
||||
UtilityShaderVertex* upload_vertices = ReserveVertices(topology, count);
|
||||
UtilityShaderVertex* upload_vertices = ReserveVertices(count);
|
||||
memcpy(upload_vertices, vertices, sizeof(UtilityShaderVertex) * count);
|
||||
CommitVertices(count);
|
||||
}
|
||||
@ -447,7 +443,12 @@ void UtilityShaderDraw::SetPSTexelBuffer(VkBufferView view)
|
||||
|
||||
void UtilityShaderDraw::SetRasterizationState(const RasterizationState& state)
|
||||
{
|
||||
m_pipeline_info.rasterization_state.bits = state.bits;
|
||||
m_pipeline_info.rasterization_state.hex = state.hex;
|
||||
}
|
||||
|
||||
void UtilityShaderDraw::SetMultisamplingState(const MultisamplingState& state)
|
||||
{
|
||||
m_pipeline_info.multisampling_state.hex = state.hex;
|
||||
}
|
||||
|
||||
void UtilityShaderDraw::SetDepthState(const DepthState& state)
|
||||
@ -506,7 +507,7 @@ void UtilityShaderDraw::DrawQuad(int x, int y, int width, int height, float z)
|
||||
vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
|
||||
UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
|
||||
UploadVertices(vertices, ArraySize(vertices));
|
||||
Draw();
|
||||
}
|
||||
|
||||
@ -535,7 +536,7 @@ void UtilityShaderDraw::DrawQuad(int dst_x, int dst_y, int dst_width, int dst_he
|
||||
vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
Util::SetViewportAndScissor(m_command_buffer, dst_x, dst_y, dst_width, dst_height);
|
||||
UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
|
||||
UploadVertices(vertices, ArraySize(vertices));
|
||||
Draw();
|
||||
}
|
||||
|
||||
@ -562,7 +563,7 @@ void UtilityShaderDraw::DrawColoredQuad(int x, int y, int width, int height, u32
|
||||
vertices[3].SetColor(color);
|
||||
|
||||
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
|
||||
UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
|
||||
UploadVertices(vertices, ArraySize(vertices));
|
||||
Draw();
|
||||
}
|
||||
|
||||
@ -571,11 +572,9 @@ void UtilityShaderDraw::SetViewportAndScissor(int x, int y, int width, int heigh
|
||||
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void UtilityShaderDraw::DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology,
|
||||
u32 vertex_count)
|
||||
void UtilityShaderDraw::DrawWithoutVertexBuffer(u32 vertex_count)
|
||||
{
|
||||
m_pipeline_info.vertex_format = nullptr;
|
||||
m_pipeline_info.primitive_topology = primitive_topology;
|
||||
|
||||
BindDescriptors();
|
||||
if (!BindPipeline())
|
||||
|
@ -131,12 +131,13 @@ class UtilityShaderDraw
|
||||
public:
|
||||
UtilityShaderDraw(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout,
|
||||
VkRenderPass render_pass, VkShaderModule vertex_shader,
|
||||
VkShaderModule geometry_shader, VkShaderModule pixel_shader);
|
||||
VkShaderModule geometry_shader, VkShaderModule pixel_shader,
|
||||
PrimitiveType primitive = PrimitiveType::TriangleStrip);
|
||||
|
||||
UtilityShaderVertex* ReserveVertices(VkPrimitiveTopology topology, size_t count);
|
||||
UtilityShaderVertex* ReserveVertices(size_t count);
|
||||
void CommitVertices(size_t count);
|
||||
|
||||
void UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices, size_t count);
|
||||
void UploadVertices(UtilityShaderVertex* vertices, size_t count);
|
||||
|
||||
u8* AllocateVSUniforms(size_t size);
|
||||
void CommitVSUniforms(size_t size);
|
||||
@ -151,6 +152,7 @@ public:
|
||||
void SetPSTexelBuffer(VkBufferView view);
|
||||
|
||||
void SetRasterizationState(const RasterizationState& state);
|
||||
void SetMultisamplingState(const MultisamplingState& state);
|
||||
void SetDepthState(const DepthState& state);
|
||||
void SetBlendState(const BlendingState& state);
|
||||
|
||||
@ -177,7 +179,7 @@ public:
|
||||
|
||||
// Draw without a vertex buffer. Assumes viewport has been initialized separately.
|
||||
void SetViewportAndScissor(int x, int y, int width, int height);
|
||||
void DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology, u32 vertex_count);
|
||||
void DrawWithoutVertexBuffer(u32 vertex_count);
|
||||
|
||||
private:
|
||||
void BindVertexBuffer();
|
||||
|
@ -138,33 +138,9 @@ void VertexManager::vFlush()
|
||||
// Figure out the number of indices to draw
|
||||
u32 index_count = IndexGenerator::GetIndexLen();
|
||||
|
||||
// Update assembly state
|
||||
// Update tracked state
|
||||
StateTracker::GetInstance()->SetVertexFormat(vertex_format);
|
||||
switch (m_current_primitive_type)
|
||||
{
|
||||
case PRIMITIVE_POINTS:
|
||||
StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
|
||||
StateTracker::GetInstance()->DisableBackFaceCulling();
|
||||
break;
|
||||
|
||||
case PRIMITIVE_LINES:
|
||||
StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
|
||||
StateTracker::GetInstance()->DisableBackFaceCulling();
|
||||
break;
|
||||
|
||||
case PRIMITIVE_TRIANGLES:
|
||||
StateTracker::GetInstance()->SetPrimitiveTopology(
|
||||
g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
||||
g_renderer->SetGenerationMode();
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for any shader stage changes
|
||||
StateTracker::GetInstance()->CheckForShaderChanges(m_current_primitive_type);
|
||||
|
||||
// Update any changed constants
|
||||
StateTracker::GetInstance()->CheckForShaderChanges();
|
||||
StateTracker::GetInstance()->UpdateVertexShaderConstants();
|
||||
StateTracker::GetInstance()->UpdateGeometryShaderConstants();
|
||||
StateTracker::GetInstance()->UpdatePixelShaderConstants();
|
||||
|
Reference in New Issue
Block a user