shader_vulkan.cpp - doesn't need math.h

This commit is contained in:
twinaphex 2019-01-19 23:02:48 +01:00
parent 8c5f4a842c
commit 1a0d5030f9

View File

@ -22,7 +22,6 @@
#include <utility> #include <utility>
#include <algorithm> #include <algorithm>
#include <string.h> #include <string.h>
#include <math.h>
#include <compat/strl.h> #include <compat/strl.h>
#include <formats/image.h> #include <formats/image.h>
@ -473,12 +472,12 @@ class Pass
struct PushConstant struct PushConstant
{ {
VkShaderStageFlags stages = 0; VkShaderStageFlags stages = 0;
vector<uint32_t> buffer; // uint32_t to have correct alignment. vector<uint32_t> buffer; /* uint32_t to have correct alignment. */
}; };
PushConstant push; PushConstant push;
}; };
// struct here since we're implementing the opaque typedef from C. /* struct here since we're implementing the opaque typedef from C. */
struct vulkan_filter_chain struct vulkan_filter_chain
{ {
public: public:
@ -750,7 +749,8 @@ bool vulkan_filter_chain::init_history()
return true; return true;
} }
// We don't need to store array element #0, since it's aliased with the actual original. /* We don't need to store array element #0,
* since it's aliased with the actual original. */
required_images--; required_images--;
original_history.reserve(required_images); original_history.reserve(required_images);
common.original_history.resize(required_images); common.original_history.resize(required_images);
@ -763,8 +763,10 @@ bool vulkan_filter_chain::init_history()
RARCH_LOG("[Vulkan filter chain]: Using history of %u frames.\n", required_images); RARCH_LOG("[Vulkan filter chain]: Using history of %u frames.\n", required_images);
// On first frame, we need to clear the textures to a known state, but we need /* On first frame, we need to clear the textures to
// a command buffer for that, so just defer to first frame. * a known state, but we need
* a command buffer for that, so just defer to first frame.
*/
require_clear = true; require_clear = true;
return true; return true;
} }
@ -775,7 +777,7 @@ bool vulkan_filter_chain::init_feedback()
bool use_feedbacks = false; bool use_feedbacks = false;
// Final pass cannot have feedback. /* Final pass cannot have feedback. */
for (unsigned i = 0; i < passes.size() - 1; i++) for (unsigned i = 0; i < passes.size() - 1; i++)
{ {
bool use_feedback = false; bool use_feedback = false;
@ -879,7 +881,7 @@ bool vulkan_filter_chain::init_ubo()
vkGetPhysicalDeviceProperties(gpu, &props); vkGetPhysicalDeviceProperties(gpu, &props);
common.ubo_alignment = props.limits.minUniformBufferOffsetAlignment; common.ubo_alignment = props.limits.minUniformBufferOffsetAlignment;
// Who knows. :) /* Who knows. :) */
if (common.ubo_alignment == 0) if (common.ubo_alignment == 0)
common.ubo_alignment = 1; common.ubo_alignment = 1;
@ -948,7 +950,7 @@ void vulkan_filter_chain::clear_history_and_feedback(VkCommandBuffer cmd)
void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd, void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd,
const VkViewport &vp) const VkViewport &vp)
{ {
// First frame, make sure our history and feedback textures are in a clean state. /* First frame, make sure our history and feedback textures are in a clean state. */
if (require_clear) if (require_clear)
{ {
clear_history_and_feedback(cmd); clear_history_and_feedback(cmd);
@ -991,7 +993,7 @@ void vulkan_filter_chain::update_history(DeferredDisposer &disposer, VkCommandBu
{ {
VkImageLayout src_layout = input_texture.layout; VkImageLayout src_layout = input_texture.layout;
// Transition input texture to something appropriate. /* Transition input texture to something appropriate. */
if (input_texture.layout != VK_IMAGE_LAYOUT_GENERAL) if (input_texture.layout != VK_IMAGE_LAYOUT_GENERAL)
{ {
vulkan_image_layout_transition_levels(cmd, vulkan_image_layout_transition_levels(cmd,
@ -1019,7 +1021,7 @@ void vulkan_filter_chain::update_history(DeferredDisposer &disposer, VkCommandBu
tmp->copy(cmd, input_texture.image, src_layout); tmp->copy(cmd, input_texture.image, src_layout);
// Transition input texture back. /* Transition input texture back. */
if (input_texture.layout != VK_IMAGE_LAYOUT_GENERAL) if (input_texture.layout != VK_IMAGE_LAYOUT_GENERAL)
{ {
vulkan_image_layout_transition_levels(cmd, vulkan_image_layout_transition_levels(cmd,
@ -1032,16 +1034,17 @@ void vulkan_filter_chain::update_history(DeferredDisposer &disposer, VkCommandBu
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
} }
// Should ring buffer, but we don't have *that* many passes. /* Should ring buffer, but we don't have *that* many passes. */
move_backward(begin(original_history), end(original_history) - 1, end(original_history)); move_backward(begin(original_history), end(original_history) - 1, end(original_history));
swap(original_history.front(), tmp); swap(original_history.front(), tmp);
} }
void vulkan_filter_chain::end_frame(VkCommandBuffer cmd) void vulkan_filter_chain::end_frame(VkCommandBuffer cmd)
{ {
// If we need to keep old frames, copy it after fragment is complete. /* If we need to keep old frames, copy it after fragment is complete.
// TODO: We can improve pipelining by figuring out which pass is the last that reads from * TODO: We can improve pipelining by figuring out which
// the history and dispatch the copy earlier. * pass is the last that reads from
* the history and dispatch the copy earlier. */
if (!original_history.empty()) if (!original_history.empty())
{ {
DeferredDisposer disposer(deferred_calls[current_sync_index]); DeferredDisposer disposer(deferred_calls[current_sync_index]);
@ -1052,7 +1055,7 @@ void vulkan_filter_chain::end_frame(VkCommandBuffer cmd)
void vulkan_filter_chain::build_viewport_pass( void vulkan_filter_chain::build_viewport_pass(
VkCommandBuffer cmd, const VkViewport &vp, const float *mvp) VkCommandBuffer cmd, const VkViewport &vp, const float *mvp)
{ {
// First frame, make sure our history and feedback textures are in a clean state. /* First frame, make sure our history and feedback textures are in a clean state. */
if (require_clear) if (require_clear)
{ {
clear_history_and_feedback(cmd); clear_history_and_feedback(cmd);
@ -1092,7 +1095,7 @@ void vulkan_filter_chain::build_viewport_pass(
passes.back()->build_commands(disposer, cmd, passes.back()->build_commands(disposer, cmd,
original, source, vp, mvp); original, source, vp, mvp);
// For feedback FBOs, swap current and previous. /* For feedback FBOs, swap current and previous. */
for (auto &pass : passes) for (auto &pass : passes)
pass->end_frame(); pass->end_frame();
} }
@ -1308,7 +1311,7 @@ bool Pass::init_pipeline_layout()
vector<VkDescriptorSetLayoutBinding> bindings; vector<VkDescriptorSetLayoutBinding> bindings;
vector<VkDescriptorPoolSize> desc_counts; vector<VkDescriptorPoolSize> desc_counts;
// Main UBO. /* Main UBO. */
VkShaderStageFlags ubo_mask = 0; VkShaderStageFlags ubo_mask = 0;
if (reflection.ubo_stage_mask & SLANG_STAGE_VERTEX_MASK) if (reflection.ubo_stage_mask & SLANG_STAGE_VERTEX_MASK)
ubo_mask |= VK_SHADER_STAGE_VERTEX_BIT; ubo_mask |= VK_SHADER_STAGE_VERTEX_BIT;
@ -1323,7 +1326,7 @@ bool Pass::init_pipeline_layout()
desc_counts.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, num_sync_indices }); desc_counts.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, num_sync_indices });
} }
// Semantic textures. /* Semantic textures. */
for (auto &semantic : reflection.semantic_textures) for (auto &semantic : reflection.semantic_textures)
{ {
for (auto &texture : semantic) for (auto &texture : semantic)
@ -1358,7 +1361,7 @@ bool Pass::init_pipeline_layout()
layout_info.setLayoutCount = 1; layout_info.setLayoutCount = 1;
layout_info.pSetLayouts = &set_layout; layout_info.pSetLayouts = &set_layout;
// Push constants /* Push constants */
VkPushConstantRange push_range = {}; VkPushConstantRange push_range = {};
if (reflection.push_constant_stage_mask && reflection.push_constant_size) if (reflection.push_constant_stage_mask && reflection.push_constant_size)
{ {
@ -1408,12 +1411,12 @@ bool Pass::init_pipeline()
if (!init_pipeline_layout()) if (!init_pipeline_layout())
return false; return false;
// Input assembly /* Input assembly */
VkPipelineInputAssemblyStateCreateInfo input_assembly = { VkPipelineInputAssemblyStateCreateInfo input_assembly = {
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
// VAO state /* VAO state */
VkVertexInputAttributeDescription attributes[2] = {{0}}; VkVertexInputAttributeDescription attributes[2] = {{0}};
VkVertexInputBindingDescription binding = {0}; VkVertexInputBindingDescription binding = {0};
@ -1437,7 +1440,7 @@ bool Pass::init_pipeline()
vertex_input.vertexAttributeDescriptionCount = 2; vertex_input.vertexAttributeDescriptionCount = 2;
vertex_input.pVertexAttributeDescriptions = attributes; vertex_input.pVertexAttributeDescriptions = attributes;
// Raster state /* Raster state */
VkPipelineRasterizationStateCreateInfo raster = { VkPipelineRasterizationStateCreateInfo raster = {
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
raster.polygonMode = VK_POLYGON_MODE_FILL; raster.polygonMode = VK_POLYGON_MODE_FILL;
@ -1448,7 +1451,7 @@ bool Pass::init_pipeline()
raster.depthBiasEnable = false; raster.depthBiasEnable = false;
raster.lineWidth = 1.0f; raster.lineWidth = 1.0f;
// Blend state /* Blend state */
VkPipelineColorBlendAttachmentState blend_attachment = {0}; VkPipelineColorBlendAttachmentState blend_attachment = {0};
VkPipelineColorBlendStateCreateInfo blend = { VkPipelineColorBlendStateCreateInfo blend = {
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
@ -1457,13 +1460,13 @@ bool Pass::init_pipeline()
blend.attachmentCount = 1; blend.attachmentCount = 1;
blend.pAttachments = &blend_attachment; blend.pAttachments = &blend_attachment;
// Viewport state /* Viewport state */
VkPipelineViewportStateCreateInfo viewport = { VkPipelineViewportStateCreateInfo viewport = {
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
viewport.viewportCount = 1; viewport.viewportCount = 1;
viewport.scissorCount = 1; viewport.scissorCount = 1;
// Depth-stencil state /* Depth-stencil state */
VkPipelineDepthStencilStateCreateInfo depth_stencil = { VkPipelineDepthStencilStateCreateInfo depth_stencil = {
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
depth_stencil.depthTestEnable = false; depth_stencil.depthTestEnable = false;
@ -1473,12 +1476,12 @@ bool Pass::init_pipeline()
depth_stencil.minDepthBounds = 0.0f; depth_stencil.minDepthBounds = 0.0f;
depth_stencil.maxDepthBounds = 1.0f; depth_stencil.maxDepthBounds = 1.0f;
// Multisample state /* Multisample state */
VkPipelineMultisampleStateCreateInfo multisample = { VkPipelineMultisampleStateCreateInfo multisample = {
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
// Dynamic state /* Dynamic state */
VkPipelineDynamicStateCreateInfo dynamic = { VkPipelineDynamicStateCreateInfo dynamic = {
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
static const VkDynamicState dynamics[] = { static const VkDynamicState dynamics[] = {
@ -1486,7 +1489,7 @@ bool Pass::init_pipeline()
dynamic.pDynamicStates = dynamics; dynamic.pDynamicStates = dynamics;
dynamic.dynamicStateCount = sizeof(dynamics) / sizeof(dynamics[0]); dynamic.dynamicStateCount = sizeof(dynamics) / sizeof(dynamics[0]);
// Shaders /* Shaders */
VkPipelineShaderStageCreateInfo shader_stages[2] = { VkPipelineShaderStageCreateInfo shader_stages[2] = {
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO },
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO },
@ -1539,16 +1542,18 @@ CommonResources::CommonResources(VkDevice device,
const VkPhysicalDeviceMemoryProperties &memory_properties) const VkPhysicalDeviceMemoryProperties &memory_properties)
: device(device) : device(device)
{ {
// The final pass uses an MVP designed for [0, 1] range VBO. /* The final pass uses an MVP designed for [0, 1] range VBO.
// For in-between passes, we just go with identity matrices, so keep it simple. * For in-between passes, we just go with identity matrices,
* so keep it simple.
*/
const float vbo_data[] = { const float vbo_data[] = {
// Offscreen /* Offscreen */
-1.0f, -1.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, +1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f,
1.0f, +1.0f, 1.0f, 1.0f, 1.0f, +1.0f, 1.0f, 1.0f,
// Final /* Final */
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, +1.0f, 0.0f, 1.0f, 0.0f, +1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
@ -1657,12 +1662,12 @@ void Pass::allocate_buffers()
{ {
if (reflection.ubo_stage_mask) if (reflection.ubo_stage_mask)
{ {
// Align /* Align */
common->ubo_offset = (common->ubo_offset + common->ubo_alignment - 1) & common->ubo_offset = (common->ubo_offset + common->ubo_alignment - 1) &
~(common->ubo_alignment - 1); ~(common->ubo_alignment - 1);
ubo_offset = common->ubo_offset; ubo_offset = common->ubo_offset;
// Allocate /* Allocate */
common->ubo_offset += reflection.ubo_size; common->ubo_offset += reflection.ubo_size;
} }
} }
@ -1719,7 +1724,7 @@ bool Pass::build()
if (!slang_reflect_spirv(vertex_shader, fragment_shader, &reflection)) if (!slang_reflect_spirv(vertex_shader, fragment_shader, &reflection))
return false; return false;
// Filter out parameters which we will never use anyways. /* Filter out parameters which we will never use anyways. */
filtered_parameters.clear(); filtered_parameters.clear();
for (i = 0; i < reflection.semantic_float_parameters.size(); i++) for (i = 0; i < reflection.semantic_float_parameters.size(); i++)
@ -1837,7 +1842,7 @@ void Pass::build_semantic_parameter(uint8_t *data, unsigned index, float value)
{ {
auto &refl = reflection.semantic_float_parameters[index]; auto &refl = reflection.semantic_float_parameters[index];
// We will have filtered out stale parameters. /* We will have filtered out stale parameters. */
if (data && refl.uniform) if (data && refl.uniform)
*reinterpret_cast<float*>(data + refl.ubo_offset) = value; *reinterpret_cast<float*>(data + refl.ubo_offset) = value;
@ -1876,7 +1881,7 @@ void Pass::build_semantic_texture_array(VkDescriptorSet set, uint8_t *buffer,
void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer, void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
const float *mvp, const Texture &original, const Texture &source) const float *mvp, const Texture &original, const Texture &source)
{ {
// MVP /* MVP */
if (buffer && reflection.semantics[SLANG_SEMANTIC_MVP].uniform) if (buffer && reflection.semantics[SLANG_SEMANTIC_MVP].uniform)
{ {
size_t offset = reflection.semantics[SLANG_SEMANTIC_MVP].ubo_offset; size_t offset = reflection.semantics[SLANG_SEMANTIC_MVP].ubo_offset;
@ -1895,7 +1900,7 @@ void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
build_identity_matrix(reinterpret_cast<float *>(push.buffer.data() + (offset >> 2))); build_identity_matrix(reinterpret_cast<float *>(push.buffer.data() + (offset >> 2)));
} }
// Output information /* Output information */
build_semantic_vec4(buffer, SLANG_SEMANTIC_OUTPUT, build_semantic_vec4(buffer, SLANG_SEMANTIC_OUTPUT,
current_framebuffer_size.width, current_framebuffer_size.height); current_framebuffer_size.width, current_framebuffer_size.height);
build_semantic_vec4(buffer, SLANG_SEMANTIC_FINAL_VIEWPORT, build_semantic_vec4(buffer, SLANG_SEMANTIC_FINAL_VIEWPORT,
@ -1904,21 +1909,21 @@ void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
build_semantic_uint(buffer, SLANG_SEMANTIC_FRAME_COUNT, build_semantic_uint(buffer, SLANG_SEMANTIC_FRAME_COUNT,
frame_count_period ? uint32_t(frame_count % frame_count_period) : uint32_t(frame_count)); frame_count_period ? uint32_t(frame_count % frame_count_period) : uint32_t(frame_count));
// Standard inputs /* Standard inputs */
build_semantic_texture(set, buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL, original); build_semantic_texture(set, buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL, original);
build_semantic_texture(set, buffer, SLANG_TEXTURE_SEMANTIC_SOURCE, source); build_semantic_texture(set, buffer, SLANG_TEXTURE_SEMANTIC_SOURCE, source);
// ORIGINAL_HISTORY[0] is an alias of ORIGINAL. /* ORIGINAL_HISTORY[0] is an alias of ORIGINAL. */
build_semantic_texture_array(set, buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY, 0, original); build_semantic_texture_array(set, buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY, 0, original);
// Parameters. /* Parameters. */
for (auto &param : filtered_parameters) for (auto &param : filtered_parameters)
{ {
float value = common->shader_preset->parameters[param.index].current; float value = common->shader_preset->parameters[param.index].current;
build_semantic_parameter(buffer, param.semantic_index, value); build_semantic_parameter(buffer, param.semantic_index, value);
} }
// Previous inputs. /* Previous inputs. */
unsigned i = 0; unsigned i = 0;
for (auto &texture : common->original_history) for (auto &texture : common->original_history)
{ {
@ -1928,7 +1933,7 @@ void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
i++; i++;
} }
// Previous passes. /* Previous passes. */
i = 0; i = 0;
for (auto &texture : common->pass_outputs) for (auto &texture : common->pass_outputs)
{ {
@ -1938,7 +1943,7 @@ void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
i++; i++;
} }
// Feedback FBOs. /* Feedback FBOs. */
i = 0; i = 0;
for (auto &texture : common->framebuffer_feedback) for (auto &texture : common->framebuffer_feedback)
{ {
@ -1948,7 +1953,7 @@ void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
i++; i++;
} }
// LUTs. /* LUTs. */
i = 0; i = 0;
for (auto &lut : common->luts) for (auto &lut : common->luts)
{ {
@ -1997,10 +2002,10 @@ void Pass::build_commands(
reflection.ubo_size); reflection.ubo_size);
} }
// The final pass is always executed inside /* The final pass is always executed inside
// another render pass since the frontend will * another render pass since the frontend will
// want to overlay various things on top for * want to overlay various things on top for
// the passes that end up on-screen. * the passes that end up on-screen. */
if (!final_pass) if (!final_pass)
{ {
/* Render. */ /* Render. */
@ -2086,7 +2091,7 @@ void Pass::build_commands(
framebuffer->generate_mips(cmd); framebuffer->generate_mips(cmd);
else else
{ {
// Barrier to sync with next pass. /* Barrier to sync with next pass. */
vulkan_image_layout_transition_levels( vulkan_image_layout_transition_levels(
cmd, cmd,
framebuffer->get_image(),VK_REMAINING_MIP_LEVELS, framebuffer->get_image(),VK_REMAINING_MIP_LEVELS,
@ -2148,19 +2153,20 @@ void Framebuffer::clear(VkCommandBuffer cmd)
void Framebuffer::generate_mips(VkCommandBuffer cmd) void Framebuffer::generate_mips(VkCommandBuffer cmd)
{ {
unsigned i; unsigned i;
// This is run every frame, so make sure /* This is run every frame, so make sure
// we aren't opting into the "lazy" way of doing this. :) * we aren't opting into the "lazy" way of doing this. :) */
VkImageMemoryBarrier barriers[2] = { VkImageMemoryBarrier barriers[2] = {
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }, { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER },
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }, { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER },
}; };
// First, transfer the input mip level to TRANSFER_SRC_OPTIMAL. /* First, transfer the input mip level to TRANSFER_SRC_OPTIMAL.
// This should allow the surface to stay compressed. * This should allow the surface to stay compressed.
// All subsequent mip-layers are now transferred into DST_OPTIMAL from * All subsequent mip-layers are now transferred into DST_OPTIMAL from
// UNDEFINED at this point. * UNDEFINED at this point.
*/
// Input /* Input */
barriers[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; barriers[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barriers[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@ -2173,7 +2179,7 @@ void Framebuffer::generate_mips(VkCommandBuffer cmd)
barriers[0].subresourceRange.levelCount = 1; barriers[0].subresourceRange.levelCount = 1;
barriers[0].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; barriers[0].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
// The rest of the mip chain /* The rest of the mip chain */
barriers[1].srcAccessMask = 0; barriers[1].srcAccessMask = 0;
barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -2196,8 +2202,9 @@ void Framebuffer::generate_mips(VkCommandBuffer cmd)
for (i = 1; i < levels; i++) for (i = 1; i < levels; i++)
{ {
// For subsequent passes, we have to transition from DST_OPTIMAL to SRC_OPTIMAL, /* For subsequent passes, we have to transition
// but only do so one mip-level at a time. * from DST_OPTIMAL to SRC_OPTIMAL,
* but only do so one mip-level at a time. */
if (i > 1) if (i > 1)
{ {
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
@ -2241,10 +2248,15 @@ void Framebuffer::generate_mips(VkCommandBuffer cmd)
1, &blit_region, VK_FILTER_LINEAR); 1, &blit_region, VK_FILTER_LINEAR);
} }
// We are now done, and we have all mip-levels except the last in TRANSFER_SRC_OPTIMAL, /* We are now done, and we have all mip-levels except
// and the last one still on TRANSFER_DST_OPTIMAL, so do a final barrier which * the last in TRANSFER_SRC_OPTIMAL,
// moves everything to SHADER_READ_ONLY_OPTIMAL in one go along with the execution barrier to next pass. * and the last one still on TRANSFER_DST_OPTIMAL,
// Read-to-read memory barrier, so only need execution barrier for first transition. * so do a final barrier which
* moves everything to SHADER_READ_ONLY_OPTIMAL in
* one go along with the execution barrier to next pass.
* Read-to-read memory barrier, so only need execution
* barrier for first transition.
*/
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barriers[0].subresourceRange.baseMipLevel = 0; barriers[0].subresourceRange.baseMipLevel = 0;
@ -2252,7 +2264,7 @@ void Framebuffer::generate_mips(VkCommandBuffer cmd)
barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// This is read-after-write barrier. /* This is read-after-write barrier. */
barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barriers[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; barriers[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barriers[1].subresourceRange.baseMipLevel = levels - 1; barriers[1].subresourceRange.baseMipLevel = levels - 1;
@ -2268,8 +2280,10 @@ void Framebuffer::generate_mips(VkCommandBuffer cmd)
0, nullptr, 0, nullptr,
2, barriers); 2, barriers);
// Next pass will wait for ALL_GRAPHICS_BIT, and since we have dstStage as FRAGMENT_SHADER, /* Next pass will wait for ALL_GRAPHICS_BIT, and since
// the dependency chain will ensure we don't start next pass until the mipchain is complete. * we have dstStage as FRAGMENT_SHADER,
* the dependency chain will ensure we don't start
* next pass until the mipchain is complete. */
} }
void Framebuffer::copy(VkCommandBuffer cmd, void Framebuffer::copy(VkCommandBuffer cmd,
@ -2336,11 +2350,12 @@ void Framebuffer::init(DeferredDisposer *disposer)
memory_properties, mem_reqs.memoryTypeBits, memory_properties, mem_reqs.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
// Can reuse already allocated memory. /* Can reuse already allocated memory. */
if (memory.size < mem_reqs.size || memory.type != alloc.memoryTypeIndex) if (memory.size < mem_reqs.size || memory.type != alloc.memoryTypeIndex)
{ {
// Memory might still be in use since we don't want to totally stall /* Memory might still be in use since we don't want
// the world for framebuffer recreation. * to totally stall
* the world for framebuffer recreation. */
if (memory.memory != VK_NULL_HANDLE && disposer) if (memory.memory != VK_NULL_HANDLE && disposer)
{ {
auto d = device; auto d = device;
@ -2385,8 +2400,8 @@ void Framebuffer::init_render_pass()
VkAttachmentReference color_ref = { 0, VkAttachmentReference color_ref = { 0,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
// We will always write to the entire framebuffer, /* We will always write to the entire framebuffer,
// so we don't really need to clear. * so we don't really need to clear. */
VkAttachmentDescription attachment = {0}; VkAttachmentDescription attachment = {0};
attachment.format = format; attachment.format = format;
attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.samples = VK_SAMPLE_COUNT_1_BIT;
@ -2435,13 +2450,13 @@ void Framebuffer::set_size(DeferredDisposer &disposer, const Size2D &size, VkFor
size.width, size.height, (unsigned)this->format); size.width, size.height, (unsigned)this->format);
{ {
// The current framebuffers, etc, might still be in use /* The current framebuffers, etc, might still be in use
// so defer deletion. * so defer deletion.
// We'll most likely be able to reuse the memory, * We'll most likely be able to reuse the memory,
// so don't free it here. * so don't free it here.
// *
// Fake lambda init captures for C++11. * Fake lambda init captures for C++11.
// */
auto d = device; auto d = device;
auto i = image; auto i = image;
auto v = view; auto v = view;
@ -2479,7 +2494,7 @@ Framebuffer::~Framebuffer()
vkFreeMemory(device, memory.memory, nullptr); vkFreeMemory(device, memory.memory, nullptr);
} }
// C glue /* C glue */
vulkan_filter_chain_t *vulkan_filter_chain_new( vulkan_filter_chain_t *vulkan_filter_chain_new(
const vulkan_filter_chain_create_info *info) const vulkan_filter_chain_create_info *info)
{ {
@ -2871,7 +2886,8 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(
if (itr != shader->parameters + shader->num_parameters) if (itr != shader->parameters + shader->num_parameters)
{ {
// Allow duplicate #pragma parameter, but only if they are exactly the same. /* Allow duplicate #pragma parameter, but
* only if they are exactly the same. */
if (meta_param.desc != itr->desc || if (meta_param.desc != itr->desc ||
meta_param.initial != itr->initial || meta_param.initial != itr->initial ||
meta_param.minimum != itr->minimum || meta_param.minimum != itr->minimum ||
@ -2914,7 +2930,7 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(
if (!output.meta.name.empty()) if (!output.meta.name.empty())
chain->set_pass_name(i, output.meta.name.c_str()); chain->set_pass_name(i, output.meta.name.c_str());
// Preset overrides. /* Preset overrides. */
if (*pass->alias) if (*pass->alias)
chain->set_pass_name(i, pass->alias); chain->set_pass_name(i, pass->alias);
@ -2929,9 +2945,10 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(
pass_info.address = wrap_to_address(pass->wrap); pass_info.address = wrap_to_address(pass->wrap);
pass_info.max_levels = 1; pass_info.max_levels = 1;
// TODO: Expose max_levels in slangp. /* TODO: Expose max_levels in slangp.
// CGP format is a bit awkward in that it uses mipmap_input, * CGP format is a bit awkward in that it uses mipmap_input,
// so we much check if next pass needs the mipmapping. * so we much check if next pass needs the mipmapping.
*/
if (next_pass && next_pass->mipmap) if (next_pass && next_pass->mipmap)
pass_info.max_levels = ~0u; pass_info.max_levels = ~0u;
@ -2940,7 +2957,7 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(
bool explicit_format = output.meta.rt_format != SLANG_FORMAT_UNKNOWN; bool explicit_format = output.meta.rt_format != SLANG_FORMAT_UNKNOWN;
// Set a reasonable default. /* Set a reasonable default. */
if (output.meta.rt_format == SLANG_FORMAT_UNKNOWN) if (output.meta.rt_format == SLANG_FORMAT_UNKNOWN)
output.meta.rt_format = SLANG_FORMAT_R8G8B8A8_UNORM; output.meta.rt_format = SLANG_FORMAT_R8G8B8A8_UNORM;
@ -2972,13 +2989,12 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(
} }
else else
{ {
// Preset overrides shader. /* Preset overrides shader.
// Kinda ugly ... * Kinda ugly ... */
if (pass->fbo.srgb_fbo) if (pass->fbo.srgb_fbo)
output.meta.rt_format = SLANG_FORMAT_R8G8B8A8_SRGB; output.meta.rt_format = SLANG_FORMAT_R8G8B8A8_SRGB;
else if (pass->fbo.fp_fbo) else if (pass->fbo.fp_fbo)
output.meta.rt_format = SLANG_FORMAT_R16G16B16A16_SFLOAT; output.meta.rt_format = SLANG_FORMAT_R16G16B16A16_SFLOAT;
///
pass_info.rt_format = glslang_format_to_vk(output.meta.rt_format); pass_info.rt_format = glslang_format_to_vk(output.meta.rt_format);
RARCH_LOG("[slang]: Using render target format %s for pass output #%u.\n", RARCH_LOG("[slang]: Using render target format %s for pass output #%u.\n",