Compare commits

...

2 Commits

19 changed files with 301 additions and 716 deletions
@@ -142,15 +142,20 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
const auto is_float = UniformDefinitions::IsFloat(member_ptr);
const auto num_elements = UniformDefinitions::NumElements(member_ptr);
const std::array zero_vec{
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
};
const Id cond = ctx.OpULessThanEqual(ctx.TypeBool(), buffer_offset, ctx.Const(0xFFFFu));
const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements));
return ctx.OpSelect(result_type, cond, val, zero);
if (num_elements > 1) {
const std::array zero_vec{
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
};
const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements));
return ctx.OpSelect(result_type, cond, val, zero);
} else {
const Id zero = is_float ? ctx.Const(0.0f) : ctx.Const(0u);
return ctx.OpSelect(result_type, cond, val, zero);
}
}
Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
@@ -11,6 +11,7 @@
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
#include "shader_recompiler/frontend/ir/modifiers.h"
#include "shader_recompiler/shader_info.h"
namespace Shader::Backend::SPIRV {
namespace {
@@ -70,8 +71,7 @@ public:
}
}
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
u32 num_derivatives, const IR::Value& offset, Id lod_clamp) {
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives, u32 num_derivatives, const IR::Value& offset, Id lod_clamp) {
if (!Sirit::ValidId(derivatives)) {
throw LogicError("Derivatives must be present");
}
@@ -81,10 +81,8 @@ public:
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2));
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1));
}
const Id derivatives_X{ctx.OpCompositeConstruct(
ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
const Id derivatives_Y{ctx.OpCompositeConstruct(
ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
const Id derivatives_X{ctx.OpCompositeConstruct(ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
const Id derivatives_Y{ctx.OpCompositeConstruct(ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
AddOffset(ctx, offset, ImageGradientOffsetAllowed);
if (has_lod_clamp) {
@@ -197,20 +195,14 @@ Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR
}
Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& index) {
if (!index.IsImmediate() || index.U32() != 0) {
throw NotImplementedException("Indirect image indexing");
}
UNIMPLEMENTED_IF_MSG(!index.IsImmediate() || index.U32() != 0, "Indirect image indexing");
if (info.type == TextureType::Buffer) {
const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)};
if (def.count > 1) {
throw NotImplementedException("Indirect texture sample");
}
return ctx.OpLoad(ctx.image_buffer_type, def.id);
UNIMPLEMENTED_IF(def.count > 1);
return ctx.OpLoad(ctx.image_buffer_types[info.descriptor_index], def.id);
} else {
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
if (def.count > 1) {
throw NotImplementedException("Indirect texture sample");
}
UNIMPLEMENTED_IF(def.count > 1);
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
}
}
@@ -533,13 +525,10 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
if (ctx.profile.need_gather_subpixel_offset) {
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
}
return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst,
ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(),
operands.Span());
return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(), operands.Span());
}
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms) {
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, Id lod, Id ms) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
AddOffsetToCoordinates(ctx, info, coords, offset);
if (info.type == TextureType::Buffer) {
@@ -549,9 +538,14 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
// This image is multisampled, lod must be implicit
lod = Id{};
}
const auto is_integer = info.type == TextureType::Buffer
? ctx.texture_buffers.at(info.descriptor_index).is_integer
: ctx.textures.at(info.descriptor_index).is_integer;
const ImageOperands operands(lod, ms);
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
auto const result = Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst,
is_integer ? ctx.U32[4] : ctx.F32[4], TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
// TODO: Is this even correct?????
return is_integer ? ctx.OpConvertUToF(ctx.F32[4], result) : result;
}
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
@@ -593,14 +587,11 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
zero, zero);
}
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, const IR::Value& offset, Id lod_clamp) {
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id derivatives, const IR::Value& offset, Id lod_clamp) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
const auto operands = info.num_derivatives == 3
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
ctx.Def(offset), {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
info.num_derivatives, offset, lod_clamp);
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, ctx.Def(offset), {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset, lod_clamp);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
@@ -30,9 +30,9 @@ enum class Operation {
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
const spv::ImageFormat format{spv::ImageFormat::Unknown};
const Id type{ctx.F32[1]};
const bool depth{desc.is_depth};
const bool ms{desc.is_multisample};
const Id type = desc.is_integer ? ctx.U32[1] : ctx.F32[1];
const bool depth = desc.is_depth;
const bool ms = desc.is_multisample;
switch (desc.type) {
case TextureType::Color1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format);
@@ -1304,22 +1304,23 @@ void EmitContext::DefineTextureBuffers(const Info& info, u32& binding) {
if (info.texture_buffer_descriptors.empty()) {
return;
}
const spv::ImageFormat format{spv::ImageFormat::Unknown};
image_buffer_type = TypeImage(F32[1], spv::Dim::Buffer, 0U, false, false, 1, format);
const Id type{TypePointer(spv::StorageClass::UniformConstant, image_buffer_type)};
const spv::ImageFormat format = spv::ImageFormat::Unknown;
texture_buffers.reserve(info.texture_buffer_descriptors.size());
for (const TextureBufferDescriptor& desc : info.texture_buffer_descriptors) {
if (desc.count != 1) {
throw NotImplementedException("Array of texture buffers");
}
const Id id{AddGlobalVariable(type, spv::StorageClass::UniformConstant)};
for (size_t i = 0; i < info.texture_buffer_descriptors.size(); ++i) {
auto const& desc = info.texture_buffer_descriptors[i];
UNIMPLEMENTED_IF(desc.count != 1);
image_buffer_types[i] = TypeImage(desc.is_integer ? U32[1] : F32[1], spv::Dim::Buffer, 0U, false, false, 1, format);
const Id type = TypePointer(spv::StorageClass::UniformConstant, image_buffer_types[i]);
const Id id = AddGlobalVariable(type, spv::StorageClass::UniformConstant);
Decorate(id, spv::Decoration::Binding, binding);
Decorate(id, spv::Decoration::DescriptorSet, 0U);
Name(id, NameOf(stage, desc, "texbuf"));
texture_buffers.push_back({
.id = id,
.count = desc.count,
.is_integer = desc.is_integer
});
if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id);
@@ -1374,6 +1375,7 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in
.image_type = image_type,
.count = desc.count,
.is_multisample = desc.is_multisample,
.is_integer = desc.is_integer
});
if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id);
@@ -41,11 +41,13 @@ struct TextureDefinition {
Id image_type;
u32 count;
bool is_multisample;
bool is_integer;
};
struct TextureBufferDefinition {
Id id;
u32 count;
bool is_integer;
};
struct ImageBufferDefinition {
@@ -248,7 +250,8 @@ public:
Id output_f32{};
Id output_u32{};
Id image_buffer_type{};
// Max TextureBuffers?
std::array<Id, Info::MAX_CBUFS> image_buffer_types{};
Id image_u32{};
std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{};
+10 -5
View File
@@ -429,7 +429,7 @@ public:
texture_descriptors{texture_descriptors_}, image_descriptors{image_descriptors_} {}
u32 Add(const TextureBufferDescriptor& desc) {
return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) {
const u32 index = Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) {
return desc.cbuf_index == existing.cbuf_index &&
desc.cbuf_offset == existing.cbuf_offset &&
desc.shift_left == existing.shift_left &&
@@ -439,6 +439,8 @@ public:
desc.count == existing.count && desc.size_shift == existing.size_shift &&
desc.has_secondary == existing.has_secondary;
});
texture_buffer_descriptors[index].is_integer |= desc.is_integer;
return index;
}
u32 Add(const ImageBufferDescriptor& desc) {
@@ -465,7 +467,8 @@ public:
desc.secondary_shift_left == existing.secondary_shift_left &&
desc.count == existing.count && desc.size_shift == existing.size_shift;
})};
// TODO: Read this from TIC
texture_descriptors[index].is_integer |= desc.is_integer;
// TODO: Read this from TIC (the MSAA whatever)
texture_descriptors[index].is_multisample |= desc.is_multisample;
return index;
}
@@ -632,6 +635,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
break;
}
u32 index;
const bool is_integer = IsTexturePixelFormatIntegerCached(env, cbuf);
switch (inst->GetOpcode()) {
case IR::Opcode::ImageRead:
case IR::Opcode::ImageAtomicIAdd32:
@@ -649,9 +653,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (cbuf.has_secondary) {
throw NotImplementedException("Unexpected separate sampler");
}
const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
const bool is_integer{IsTexturePixelFormatIntegerCached(env, cbuf)};
const bool is_written = inst->GetOpcode() != IR::Opcode::ImageRead;
const bool is_read = inst->GetOpcode() != IR::Opcode::ImageWrite;
if (flags.type == TextureType::Buffer) {
index = descriptors.Add(ImageBufferDescriptor{
.format = flags.image_format,
@@ -682,6 +685,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (flags.type == TextureType::Buffer) {
index = descriptors.Add(TextureBufferDescriptor{
.has_secondary = cbuf.has_secondary,
.is_integer = is_integer,
.cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset,
.shift_left = cbuf.shift_left,
@@ -696,6 +700,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.type = flags.type,
.is_depth = flags.is_depth != 0,
.is_multisample = is_multisample,
.is_integer = is_integer,
.has_secondary = cbuf.has_secondary,
.cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset,
+2
View File
@@ -178,6 +178,7 @@ struct StorageBufferDescriptor {
struct TextureBufferDescriptor {
bool has_secondary;
bool is_integer;
u32 cbuf_index;
u32 cbuf_offset;
u32 shift_left;
@@ -209,6 +210,7 @@ struct TextureDescriptor {
TextureType type;
bool is_depth;
bool is_multisample;
bool is_integer;
bool has_secondary;
u32 cbuf_index;
u32 cbuf_offset;
+1 -17
View File
@@ -436,23 +436,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
.layerCount = 1,
},
};
// Blit image barrier - transition can happen at any stage
// Using specific stages for better parallelism, but keeping broad since this is a general utility
const VkPipelineStageFlags src_stages_blit =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
const VkPipelineStageFlags dst_stages_blit =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_blit, dst_stages_blit,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, barrier);
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -68,16 +68,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
.layerCount = 1,
},
};
// Present path - use specific stages for better parallelism on tile-based GPUs
const VkPipelineStageFlags src_stages =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
const VkPipelineStageFlags dst_stages =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages, dst_stages,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, barrier);
}
@@ -160,12 +151,11 @@ void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffe
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
// Host will read the downloaded data
static constexpr VkMemoryBarrier memory_write_barrier{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
const VkBufferImageCopy copy{
.bufferOffset = 0,
@@ -180,20 +170,10 @@ void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffe
.imageOffset{.x = 0, .y = 0, .z = 0},
.imageExtent{extent},
};
const VkPipelineStageFlags src_stages_copy =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_copy, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
read_barrier);
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy);
const VkPipelineStageFlags dst_stages_copy =
VK_PIPELINE_STAGE_HOST_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_copy, 0,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
memory_write_barrier, nullptr, image_write_barrier);
}
@@ -436,27 +436,13 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer,
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) {
if (barrier) {
// Buffer writes can come from vertex input, shaders, or compute
const VkPipelineStageFlags src_stages =
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
}
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
if (barrier) {
// Buffer reads can go to vertex input, shaders, or compute
const VkPipelineStageFlags dst_stages =
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
dst_stages, 0, WRITE_BARRIER);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
}
});
}
@@ -470,36 +456,21 @@ void BufferCacheRuntime::PreCopyBarrier() {
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([](vk::CommandBuffer cmdbuf) {
const VkPipelineStageFlags src_stages =
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, READ_BARRIER);
});
}
void BufferCacheRuntime::PostCopyBarrier() {
// Specific access flags for buffer destinations: vertex input, uniforms, storage, index
static constexpr VkMemoryBarrier WRITE_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([](vk::CommandBuffer cmdbuf) {
const VkPipelineStageFlags dst_stages =
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, WRITE_BARRIER);
});
}
@@ -523,24 +494,10 @@ void BufferCacheRuntime::ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t si
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([dest_buffer, offset, size, value](vk::CommandBuffer cmdbuf) {
// Buffer writes can come from vertex input, shaders, or compute
const VkPipelineStageFlags src_stages_clear =
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_clear, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, READ_BARRIER);
cmdbuf.FillBuffer(dest_buffer, offset, size, value);
// Buffer reads can go to vertex input, shaders, or compute
const VkPipelineStageFlags dst_stages_clear =
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_clear,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, WRITE_BARRIER);
});
}
@@ -446,26 +446,13 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
const VkDescriptorSet set = descriptor_allocator.Commit();
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
// Memory writes can come from graphics or compute stages
const VkPipelineStageFlags src_stages_compute =
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_compute,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
cmdbuf.Dispatch(1, 1, 1);
// Conditional rendering result used by draw indirect or conditional rendering
const VkPipelineStageFlags dst_stages_cond =
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
dst_stages_cond, 0, write_barrier);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
});
}
@@ -533,29 +520,14 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
const VkDescriptorSet set = descriptor_allocator.Commit();
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
// Memory writes can come from graphics or compute stages
const VkPipelineStageFlags src_stages_scan =
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_scan,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
cmdbuf.Dispatch(1, 1, 1);
// Query prefix scan results used by draw indirect, conditional rendering, or shaders
const VkPipelineStageFlags dst_stages_scan =
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT |
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
dst_stages_scan, 0, write_barrier);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
});
}
}
@@ -607,15 +579,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
// If initialized, memory writes can come from graphics or compute stages
const VkPipelineStageFlags src_stages_astc = is_initialized ?
(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT) :
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
cmdbuf.PipelineBarrier(src_stages_astc,
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
});
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -441,13 +441,7 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) {
},
};
// Previous operations that might have written to the frame image
const VkPipelineStageFlags src_stages_present =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_present, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
{}, {}, pre_barriers);
if (blit_supported) {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -809,19 +809,12 @@ public:
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([](vk::CommandBuffer cmdbuf) {
// After transfer, results may be read by host or used in subsequent operations
const VkPipelineStageFlags dst_stages_query =
VK_PIPELINE_STAGE_HOST_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
dst_stages_query, 0, WRITE_BARRIER);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
});
std::scoped_lock lk(flush_guard);
@@ -949,7 +942,7 @@ private:
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([dst_buffer = current_bank->GetBuffer(),
@@ -1482,40 +1475,22 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
};
// Query results may be read by host or used in shaders/indirect commands
static constexpr VkMemoryBarrier WRITE_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
impl->scheduler.RequestOutsideRenderPassOperationContext();
if (is_prebarrier) {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
// Query data can be written by graphics or compute stages
const VkPipelineStageFlags src_stages_query =
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_query,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
});
} else {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
// Query results may be read by host or used in shaders/indirect commands
const VkPipelineStageFlags dst_stages_query =
VK_PIPELINE_STAGE_HOST_BIT |
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
dst_stages_query, 0, WRITE_BARRIER);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
});
}
}
@@ -586,23 +586,14 @@ void RasterizerVulkan::DispatchCompute() {
}
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
scheduler.RequestOutsideRenderPassOperationContext();
// Compute shader reads from storage buffers, uniforms, and images
static constexpr VkMemoryBarrier READ_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
};
scheduler.Record([](vk::CommandBuffer cmdbuf) {
// Memory writes can come from graphics or compute stages
const VkPipelineStageFlags src_stages =
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, READ_BARRIER);
});
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, READ_BARRIER); });
scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); });
// Log compute dispatch
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -44,19 +44,13 @@ using VideoCore::Surface::SurfaceType;
}
VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format,
VkSampleCountFlagBits samples,
bool is_depth_stencil) {
VkSampleCountFlagBits samples) {
using MaxwellToVK::SurfaceFormat;
const SurfaceType surface_type = GetSurfaceType(format);
const bool has_stencil = surface_type == SurfaceType::DepthStencil ||
surface_type == SurfaceType::Stencil;
// Use optimal layouts for attachments - this allows drivers to optimize tiling and access patterns
const VkImageLayout attachment_layout = is_depth_stencil
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
return {
.flags = {},
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
@@ -67,8 +61,8 @@ using VideoCore::Surface::SurfaceType;
: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = has_stencil ? VK_ATTACHMENT_STORE_OP_STORE
: VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = attachment_layout,
.finalLayout = attachment_layout,
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
};
}
} // Anonymous namespace
@@ -90,10 +84,10 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
const bool is_valid{format != PixelFormat::Invalid};
references[index] = VkAttachmentReference{
.attachment = is_valid ? num_colors : VK_ATTACHMENT_UNUSED,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.layout = VK_IMAGE_LAYOUT_GENERAL,
};
if (is_valid) {
descriptions.push_back(AttachmentDescription(*device, format, key.samples, false));
descriptions.push_back(AttachmentDescription(*device, format, key.samples));
num_attachments = static_cast<u32>(index + 1);
++num_colors;
}
@@ -103,9 +97,9 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
if (key.depth_format != PixelFormat::Invalid) {
depth_reference = VkAttachmentReference{
.attachment = num_colors,
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
.layout = VK_IMAGE_LAYOUT_GENERAL,
};
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples, true));
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples));
}
const VkSubpassDescription subpass{
.flags = 0,
+22 -72
View File
@@ -264,26 +264,14 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se
const u64 signal_value = master_semaphore->NextTick();
RecordWithUploadBuffer([signal_semaphore, wait_semaphore, signal_value,
this](vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf) {
// Specific access flags for upload destinations: vertex input, uniforms, storage, index, textures
static constexpr VkMemoryBarrier WRITE_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
// Specify exact stages that need the transfer results instead of ALL_COMMANDS_BIT
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
0, WRITE_BARRIER);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
upload_cmdbuf.End();
cmdbuf.End();
@@ -344,11 +332,11 @@ void Scheduler::EndRenderPass()
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
query_cache->NotifySegment(false);
Record([num_images = num_renderpass_images,
images = renderpass_images,
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
std::array<VkImageMemoryBarrier, 9> barriers;
VkPipelineStageFlags src_stages = 0;
for (size_t i = 0; i < num_images; ++i) {
const VkImageSubresourceRange& range = ranges[i];
const bool is_color = (range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
@@ -356,76 +344,38 @@ void Scheduler::EndRenderPass()
& (VK_IMAGE_ASPECT_DEPTH_BIT
| VK_IMAGE_ASPECT_STENCIL_BIT)) !=0;
// Determine optimal destination layout based on image usage
// After render pass, images may be used as shader resources or as attachments again
// Use optimal layouts to allow driver optimizations
VkAccessFlags src_access = 0;
VkAccessFlags dst_access = 0;
VkPipelineStageFlags this_stage = 0;
VkImageLayout new_layout;
if (is_color) {
// Color attachments can be read as textures or used as attachments again
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
this_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
dst_access = VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else if (is_depth_stencil) {
// Depth attachments can be read as textures or used as attachments again
src_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
this_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
dst_access = VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
} else {
// Fallback to GENERAL for unknown usage
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
this_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
new_layout = VK_IMAGE_LAYOUT_GENERAL;
dst_access = VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
src_stages |= this_stage;
if (is_color)
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
else if (is_depth_stencil)
src_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
else
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
barriers[i] = VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = src_access,
.dstAccessMask = dst_access,
.oldLayout = is_color ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
: (is_depth_stencil ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
: VK_IMAGE_LAYOUT_GENERAL),
.newLayout = new_layout,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = images[i],
.subresourceRange = range,
};
}
cmdbuf.EndRenderPass();
// Use specific pipeline stages instead of ALL_COMMANDS_BIT for better parallelism
// The destination stages depend on how the images will be used next
const VkPipelineStageFlags dst_stages =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cmdbuf.PipelineBarrier(src_stages,
dst_stages,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0,
nullptr,
nullptr,
@@ -810,8 +810,7 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@@ -823,8 +822,7 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@@ -833,26 +831,11 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
.subresourceRange = subresource_range,
},
};
// Use specific pipeline stages for better parallelism
const VkPipelineStageFlags src_stages =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, nullptr, nullptr, read_barriers);
cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions, vk_filter);
// After transfer, images may be used in graphics, compute, or as attachments
const VkPipelineStageFlags dst_stages =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, nullptr, nullptr, write_barriers);
});
}
@@ -1038,12 +1021,11 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
};
// After reinterpret, buffers used as transfer source, uniforms, or storage
static constexpr VkMemoryBarrier WRITE_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
const std::array pre_barriers{
VkImageMemoryBarrier{
@@ -1110,39 +1092,18 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
.subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
},
};
const VkPipelineStageFlags src_stages_transfer =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_transfer, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, {}, {}, pre_barriers);
cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
vk_in_copies);
const VkPipelineStageFlags dst_stages_transfer =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_transfer,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, WRITE_BARRIER, nullptr, middle_in_barrier);
cmdbuf.PipelineBarrier(src_stages_transfer, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, READ_BARRIER, {}, middle_out_barrier);
cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies);
// After reinterpret copy, image may be used in shaders or as attachment
const VkPipelineStageFlags dst_stages_post =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_post,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, {}, {}, post_barriers);
});
}
@@ -1269,12 +1230,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
const VkPipelineStageFlags src_stages_resolve =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_resolve, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, nullptr, nullptr, read_barriers);
if (is_resolve) {
cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
@@ -1287,14 +1243,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter);
}
// After blit/resolve, image may be used in shaders or as attachment
const VkPipelineStageFlags dst_stages_blit =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_blit,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, write_barrier);
});
}
@@ -1872,14 +1821,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
const VkPipelineStageFlags src_stages_download =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_download, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, read_barrier);
for (size_t index = 0; index < buffers.size(); index++) {
@@ -1887,20 +1829,17 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
vk_copies[index]);
}
// Host will read the downloaded data
const VkMemoryBarrier memory_write_barrier{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
// Image will be used for shaders or as attachment
const VkImageMemoryBarrier image_write_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@@ -1914,13 +1853,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
const VkPipelineStageFlags dst_stages_download =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_download,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, memory_write_barrier, nullptr, image_write_barrier);
});
return;
@@ -1955,15 +1888,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
// Image writes can come from graphics or compute stages
const VkPipelineStageFlags src_stages_img =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(src_stages_img, VK_PIPELINE_STAGE_TRANSFER_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, read_barrier);
for (size_t index = 0; index < buffers.size(); index++) {
@@ -1995,14 +1920,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
// After download, image may be used in shaders or as attachment
const VkPipelineStageFlags dst_stages_img =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_img,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, memory_write_barrier, nullptr, image_write_barrier);
});
}
@@ -2556,9 +2474,7 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_NONE,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@@ -2574,16 +2490,8 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([barrier](vk::CommandBuffer cmdbuf) {
// After layout transition, image may be used in shaders or as attachment
const VkPipelineStageFlags dst_stages_layout =
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
dst_stages_layout, 0, barrier);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
});
}
}
+4 -9
View File
@@ -65,9 +65,7 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en
}
static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) {
return static_cast<Shader::TexturePixelFormat>(
PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type,
entry.a_type, entry.srgb_conversion));
return Shader::TexturePixelFormat(PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, entry.a_type, entry.srgb_conversion));
}
static std::string_view StageToPrefix(Shader::Stage stage) {
@@ -388,8 +386,7 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl
}
bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
return VideoCore::Surface::IsPixelFormatInteger(VideoCore::Surface::PixelFormat(ReadTexturePixelFormat(handle)));
}
u32 GraphicsEnvironment::ReadViewportTransformState() {
@@ -443,8 +440,7 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle
}
bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
return VideoCore::Surface::IsPixelFormatInteger(VideoCore::Surface::PixelFormat(ReadTexturePixelFormat(handle)));
}
u32 ComputeEnvironment::ReadViewportTransformState() {
@@ -551,8 +547,7 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) {
}
bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
return VideoCore::Surface::IsPixelFormatInteger(VideoCore::Surface::PixelFormat(ReadTexturePixelFormat(handle)));
}
u32 FileEnvironment::ReadViewportTransformState() {
+34 -34
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
@@ -242,39 +242,39 @@ SurfaceType GetFormatType(PixelFormat pixel_format) {
bool HasAlpha(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::A8B8G8R8_UNORM:
case PixelFormat::A8B8G8R8_SNORM:
case PixelFormat::A8B8G8R8_SINT:
case PixelFormat::A8B8G8R8_UINT:
case PixelFormat::A1R5G5B5_UNORM:
case PixelFormat::A2B10G10R10_UNORM:
case PixelFormat::A2B10G10R10_UINT:
case PixelFormat::A2R10G10B10_UNORM:
case PixelFormat::A1B5G5R5_UNORM:
case PixelFormat::A5B5G5R1_UNORM:
case PixelFormat::R16G16B16A16_FLOAT:
case PixelFormat::R16G16B16A16_UNORM:
case PixelFormat::R16G16B16A16_SNORM:
case PixelFormat::R16G16B16A16_SINT:
case PixelFormat::R16G16B16A16_UINT:
case PixelFormat::R32G32B32A32_UINT:
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::B8G8R8A8_UNORM:
case PixelFormat::R32G32B32A32_FLOAT:
case PixelFormat::R32G32B32A32_SINT:
case PixelFormat::A8B8G8R8_SRGB:
case PixelFormat::B8G8R8A8_SRGB:
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::A4B4G4R4_UNORM:
case PixelFormat::BC2_SRGB:
case PixelFormat::BC2_UNORM:
case PixelFormat::BC3_SRGB:
case PixelFormat::BC3_UNORM:
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM:
return true;
default:
return false;
case PixelFormat::A8B8G8R8_UNORM:
case PixelFormat::A8B8G8R8_SNORM:
case PixelFormat::A8B8G8R8_SINT:
case PixelFormat::A8B8G8R8_UINT:
case PixelFormat::A1R5G5B5_UNORM:
case PixelFormat::A2B10G10R10_UNORM:
case PixelFormat::A2B10G10R10_UINT:
case PixelFormat::A2R10G10B10_UNORM:
case PixelFormat::A1B5G5R5_UNORM:
case PixelFormat::A5B5G5R1_UNORM:
case PixelFormat::R16G16B16A16_FLOAT:
case PixelFormat::R16G16B16A16_UNORM:
case PixelFormat::R16G16B16A16_SNORM:
case PixelFormat::R16G16B16A16_SINT:
case PixelFormat::R16G16B16A16_UINT:
case PixelFormat::R32G32B32A32_UINT:
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::B8G8R8A8_UNORM:
case PixelFormat::R32G32B32A32_FLOAT:
case PixelFormat::R32G32B32A32_SINT:
case PixelFormat::A8B8G8R8_SRGB:
case PixelFormat::B8G8R8A8_SRGB:
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::A4B4G4R4_UNORM:
case PixelFormat::BC2_SRGB:
case PixelFormat::BC2_UNORM:
case PixelFormat::BC3_SRGB:
case PixelFormat::BC3_UNORM:
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM:
return true;
default:
return false;
}
}
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,243 +14,124 @@ using Tegra::Texture::ComponentType;
using Tegra::Texture::TextureFormat;
using VideoCore::Surface::PixelFormat;
namespace {
constexpr auto SNORM = ComponentType::SNORM;
constexpr auto UNORM = ComponentType::UNORM;
constexpr auto SINT = ComponentType::SINT;
constexpr auto UINT = ComponentType::UINT;
constexpr auto FLOAT = ComponentType::FLOAT;
constexpr bool LINEAR = false;
constexpr bool SRGB = true;
constexpr u32 Hash(TextureFormat format, ComponentType red_component, ComponentType green_component,
ComponentType blue_component, ComponentType alpha_component, bool is_srgb) {
u32 hash = is_srgb ? 1 : 0;
hash |= static_cast<u32>(red_component) << 1;
hash |= static_cast<u32>(green_component) << 4;
hash |= static_cast<u32>(blue_component) << 7;
hash |= static_cast<u32>(alpha_component) << 10;
hash |= static_cast<u32>(format) << 13;
return hash;
}
// (TF2PF_ELEM[A-Z_0-9(]+, )([A-Z]+)(, LINEAR|. SRGB)
// $1$2, $2, $2, $2$3
#define TF2PF_LIST \
TF2PF_ELEM(A8B8G8R8, UNORM, UNORM, UNORM, UNORM, LINEAR, A8B8G8R8_UNORM) \
TF2PF_ELEM(A8B8G8R8, UNORM, UNORM, UNORM, UNORM, SRGB, A8B8G8R8_SRGB) \
TF2PF_ELEM(A8B8G8R8, SNORM, SNORM, SNORM, SNORM, LINEAR, A8B8G8R8_SNORM) \
TF2PF_ELEM(A8B8G8R8, UINT, UINT, UINT, UINT, LINEAR, A8B8G8R8_UINT) \
TF2PF_ELEM(A8B8G8R8, SINT, SINT, SINT, SINT, LINEAR, A8B8G8R8_SINT) \
TF2PF_ELEM(B5G6R5, UNORM, UNORM, UNORM, UNORM, LINEAR, B5G6R5_UNORM) \
TF2PF_ELEM(A2B10G10R10, UNORM, UNORM, UNORM, UNORM, LINEAR, A2B10G10R10_UNORM) \
TF2PF_ELEM(A2B10G10R10, UINT, UINT, UINT, UINT, LINEAR, A2B10G10R10_UINT) \
TF2PF_ELEM(A1B5G5R5, UNORM, UNORM, UNORM, UNORM, LINEAR, A1B5G5R5_UNORM) \
TF2PF_ELEM(A4B4G4R4, UNORM, UNORM, UNORM, UNORM, LINEAR, A4B4G4R4_UNORM) \
TF2PF_ELEM(G4R4, UNORM, UNORM, UNORM, UNORM, LINEAR, G4R4_UNORM) \
TF2PF_ELEM(A5B5G5R1, UNORM, UNORM, UNORM, UNORM, LINEAR, A5B5G5R1_UNORM) \
TF2PF_ELEM(R8, UNORM, UNORM, UNORM, UNORM, LINEAR, R8_UNORM) \
TF2PF_ELEM(R8, SNORM, SNORM, SNORM, SNORM, LINEAR, R8_SNORM) \
TF2PF_ELEM(R8, UINT, UINT, UINT, UINT, LINEAR, R8_UINT) \
TF2PF_ELEM(R8, SINT, SINT, SINT, SINT, LINEAR, R8_SINT) \
TF2PF_ELEM(G8R8, UNORM, UNORM, UNORM, UNORM, LINEAR, R8G8_UNORM) \
TF2PF_ELEM(G8R8, SNORM, SNORM, SNORM, SNORM, LINEAR, R8G8_SNORM) \
TF2PF_ELEM(G8R8, UINT, UINT, UINT, UINT, LINEAR, R8G8_UINT) \
TF2PF_ELEM(G8R8, SINT, SINT, SINT, SINT, LINEAR, R8G8_SINT) \
TF2PF_ELEM(R16G16B16A16, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R16G16B16A16_FLOAT) \
TF2PF_ELEM(R16G16B16A16, UNORM, UNORM, UNORM, UNORM, LINEAR, R16G16B16A16_UNORM) \
TF2PF_ELEM(R16G16B16A16, SNORM, SNORM, SNORM, SNORM, LINEAR, R16G16B16A16_SNORM) \
TF2PF_ELEM(R16G16B16A16, UINT, UINT, UINT, UINT, LINEAR, R16G16B16A16_UINT) \
TF2PF_ELEM(R16G16B16A16, SINT, SINT, SINT, SINT, LINEAR, R16G16B16A16_SINT) \
TF2PF_ELEM(R16G16, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R16G16_FLOAT) \
TF2PF_ELEM(R16G16, UNORM, UNORM, UNORM, UNORM, LINEAR, R16G16_UNORM) \
TF2PF_ELEM(R16G16, SNORM, SNORM, SNORM, SNORM, LINEAR, R16G16_SNORM) \
TF2PF_ELEM(R16G16, UINT, UINT, UINT, UINT, LINEAR, R16G16_UINT) \
TF2PF_ELEM(R16G16, SINT, SINT, SINT, SINT, LINEAR, R16G16_SINT) \
TF2PF_ELEM(R16, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R16_FLOAT) \
TF2PF_ELEM(R16, UNORM, UNORM, UNORM, UNORM, LINEAR, R16_UNORM) \
TF2PF_ELEM(R16, SNORM, SNORM, SNORM, SNORM, LINEAR, R16_SNORM) \
TF2PF_ELEM(R16, UINT, UINT, UINT, UINT, LINEAR, R16_UINT) \
TF2PF_ELEM(R16, SINT, SINT, SINT, SINT, LINEAR, R16_SINT) \
TF2PF_ELEM(B10G11R11, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, B10G11R11_FLOAT) \
TF2PF_ELEM(R32G32B32A32, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R32G32B32A32_FLOAT) \
TF2PF_ELEM(R32G32B32A32, UINT, UINT, UINT, UINT, LINEAR, R32G32B32A32_UINT) \
TF2PF_ELEM(R32G32B32A32, SINT, SINT, SINT, SINT, LINEAR, R32G32B32A32_SINT) \
TF2PF_ELEM(R32G32B32, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R32G32B32_FLOAT) \
TF2PF_ELEM(R32G32, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R32G32_FLOAT) \
TF2PF_ELEM(R32G32, UINT, UINT, UINT, UINT, LINEAR, R32G32_UINT) \
TF2PF_ELEM(R32G32, SINT, SINT, SINT, SINT, LINEAR, R32G32_SINT) \
TF2PF_ELEM(R32, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, R32_FLOAT) \
TF2PF_ELEM(R32, UINT, UINT, UINT, UINT, LINEAR, R32_UINT) \
TF2PF_ELEM(R32, SINT, SINT, SINT, SINT, LINEAR, R32_SINT) \
TF2PF_ELEM(E5B9G9R9, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, E5B9G9R9_FLOAT) \
TF2PF_ELEM(Z32, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, D32_FLOAT) \
TF2PF_ELEM(Z32, FLOAT, UINT, UINT, UINT, LINEAR, D32_FLOAT) \
TF2PF_ELEM(Z16, UNORM, UNORM, UNORM, UNORM, LINEAR, D16_UNORM) \
TF2PF_ELEM(Z16, UNORM, UINT, UINT, UINT, LINEAR, D16_UNORM) \
TF2PF_ELEM(X8Z24, UNORM, UNORM, UNORM, UNORM, LINEAR, X8_D24_UNORM) \
TF2PF_ELEM(X8Z24, UNORM, UINT, UINT, UINT, LINEAR, X8_D24_UNORM) \
TF2PF_ELEM(Z24S8, UINT, UNORM, UNORM, UNORM, LINEAR, S8_UINT_D24_UNORM) \
TF2PF_ELEM(Z24S8, UINT, UNORM, UINT, UINT, LINEAR, S8_UINT_D24_UNORM) \
TF2PF_ELEM(G24R8, UINT, UNORM, UNORM, UNORM, LINEAR, S8_UINT_D24_UNORM) \
TF2PF_ELEM(S8Z24, UNORM, UINT, UINT, UINT, LINEAR, D24_UNORM_S8_UINT) \
TF2PF_ELEM(Z32_X24S8, FLOAT, UINT, UNORM, UNORM, LINEAR, D32_FLOAT_S8_UINT) \
TF2PF_ELEM(R32B24G8, FLOAT, UINT, UNORM, UNORM, LINEAR, D32_FLOAT_S8_UINT) \
TF2PF_ELEM(DXT1, UNORM, UNORM, UNORM, UNORM, LINEAR, BC1_RGBA_UNORM) \
TF2PF_ELEM(DXT1, UNORM, UNORM, UNORM, UNORM, SRGB, BC1_RGBA_SRGB) \
TF2PF_ELEM(DXT23, UNORM, UNORM, UNORM, UNORM, LINEAR, BC2_UNORM) \
TF2PF_ELEM(DXT23, UNORM, UNORM, UNORM, UNORM, SRGB, BC2_SRGB) \
TF2PF_ELEM(DXT45, UNORM, UNORM, UNORM, UNORM, LINEAR, BC3_UNORM) \
TF2PF_ELEM(DXT45, UNORM, UNORM, UNORM, UNORM, SRGB, BC3_SRGB) \
TF2PF_ELEM(DXN1, UNORM, UNORM, UNORM, UNORM, LINEAR, BC4_UNORM) \
TF2PF_ELEM(DXN1, SNORM, SNORM, SNORM, SNORM, LINEAR, BC4_SNORM) \
TF2PF_ELEM(DXN2, UNORM, UNORM, UNORM, UNORM, LINEAR, BC5_UNORM) \
TF2PF_ELEM(DXN2, SNORM, SNORM, SNORM, SNORM, LINEAR, BC5_SNORM) \
TF2PF_ELEM(BC7U, UNORM, UNORM, UNORM, UNORM, LINEAR, BC7_UNORM) \
TF2PF_ELEM(BC7U, UNORM, UNORM, UNORM, UNORM, SRGB, BC7_SRGB) \
TF2PF_ELEM(BC6H_S16, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, BC6H_SFLOAT) \
TF2PF_ELEM(BC6H_U16, FLOAT, FLOAT, FLOAT, FLOAT, LINEAR, BC6H_UFLOAT) \
TF2PF_ELEM(ASTC_2D_4X4, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_4X4_UNORM) \
TF2PF_ELEM(ASTC_2D_4X4, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_4X4_SRGB) \
TF2PF_ELEM(ASTC_2D_5X4, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_5X4_UNORM) \
TF2PF_ELEM(ASTC_2D_5X4, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_5X4_SRGB) \
TF2PF_ELEM(ASTC_2D_5X5, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_5X5_UNORM) \
TF2PF_ELEM(ASTC_2D_5X5, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_5X5_SRGB) \
TF2PF_ELEM(ASTC_2D_8X8, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_8X8_UNORM) \
TF2PF_ELEM(ASTC_2D_8X8, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_8X8_SRGB) \
TF2PF_ELEM(ASTC_2D_8X5, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_8X5_UNORM) \
TF2PF_ELEM(ASTC_2D_8X5, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_8X5_SRGB) \
TF2PF_ELEM(ASTC_2D_10X8, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_10X8_UNORM) \
TF2PF_ELEM(ASTC_2D_10X8, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_10X8_SRGB) \
TF2PF_ELEM(ASTC_2D_6X6, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_6X6_UNORM) \
TF2PF_ELEM(ASTC_2D_6X6, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_6X6_SRGB) \
TF2PF_ELEM(ASTC_2D_10X6, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_10X6_UNORM) \
TF2PF_ELEM(ASTC_2D_10X6, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_10X6_SRGB) \
TF2PF_ELEM(ASTC_2D_10X5, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_10X5_UNORM) \
TF2PF_ELEM(ASTC_2D_10X5, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_10X5_SRGB) \
TF2PF_ELEM(ASTC_2D_10X10, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_10X10_UNORM) \
TF2PF_ELEM(ASTC_2D_10X10, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_10X10_SRGB) \
TF2PF_ELEM(ASTC_2D_12X10, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_12X10_UNORM) \
TF2PF_ELEM(ASTC_2D_12X10, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_12X10_SRGB) \
TF2PF_ELEM(ASTC_2D_12X12, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_12X12_UNORM) \
TF2PF_ELEM(ASTC_2D_12X12, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_12X12_SRGB) \
TF2PF_ELEM(ASTC_2D_8X6, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_8X6_UNORM) \
TF2PF_ELEM(ASTC_2D_8X6, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_8X6_SRGB) \
TF2PF_ELEM(ASTC_2D_6X5, UNORM, UNORM, UNORM, UNORM, LINEAR, ASTC_2D_6X5_UNORM) \
TF2PF_ELEM(ASTC_2D_6X5, UNORM, UNORM, UNORM, UNORM, SRGB, ASTC_2D_6X5_SRGB) \
constexpr u32 Hash(TextureFormat format, ComponentType component, bool is_srgb = LINEAR) {
return Hash(format, component, component, component, component, is_srgb);
}
} // Anonymous namespace
PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red, ComponentType green,
ComponentType blue, ComponentType alpha,
bool is_srgb) noexcept {
switch (Hash(format, red, green, blue, alpha, is_srgb)) {
case Hash(TextureFormat::A8B8G8R8, UNORM):
return PixelFormat::A8B8G8R8_UNORM;
case Hash(TextureFormat::A8B8G8R8, SNORM):
return PixelFormat::A8B8G8R8_SNORM;
case Hash(TextureFormat::A8B8G8R8, UINT):
return PixelFormat::A8B8G8R8_UINT;
case Hash(TextureFormat::A8B8G8R8, SINT):
return PixelFormat::A8B8G8R8_SINT;
case Hash(TextureFormat::A8B8G8R8, UNORM, SRGB):
return PixelFormat::A8B8G8R8_SRGB;
case Hash(TextureFormat::B5G6R5, UNORM):
return PixelFormat::B5G6R5_UNORM;
case Hash(TextureFormat::A2B10G10R10, UNORM):
return PixelFormat::A2B10G10R10_UNORM;
case Hash(TextureFormat::A2B10G10R10, UINT):
return PixelFormat::A2B10G10R10_UINT;
case Hash(TextureFormat::A1B5G5R5, UNORM):
return PixelFormat::A1B5G5R5_UNORM;
case Hash(TextureFormat::A4B4G4R4, UNORM):
return PixelFormat::A4B4G4R4_UNORM;
case Hash(TextureFormat::G4R4, UNORM):
return PixelFormat::G4R4_UNORM;
case Hash(TextureFormat::A5B5G5R1, UNORM):
return PixelFormat::A5B5G5R1_UNORM;
case Hash(TextureFormat::R8, UNORM):
return PixelFormat::R8_UNORM;
case Hash(TextureFormat::R8, SNORM):
return PixelFormat::R8_SNORM;
case Hash(TextureFormat::R8, UINT):
return PixelFormat::R8_UINT;
case Hash(TextureFormat::R8, SINT):
return PixelFormat::R8_SINT;
case Hash(TextureFormat::G8R8, UNORM):
return PixelFormat::R8G8_UNORM;
case Hash(TextureFormat::G8R8, SNORM):
return PixelFormat::R8G8_SNORM;
case Hash(TextureFormat::G8R8, UINT):
return PixelFormat::R8G8_UINT;
case Hash(TextureFormat::G8R8, SINT):
return PixelFormat::R8G8_SINT;
case Hash(TextureFormat::R16G16B16A16, FLOAT):
return PixelFormat::R16G16B16A16_FLOAT;
case Hash(TextureFormat::R16G16B16A16, UNORM):
return PixelFormat::R16G16B16A16_UNORM;
case Hash(TextureFormat::R16G16B16A16, SNORM):
return PixelFormat::R16G16B16A16_SNORM;
case Hash(TextureFormat::R16G16B16A16, UINT):
return PixelFormat::R16G16B16A16_UINT;
case Hash(TextureFormat::R16G16B16A16, SINT):
return PixelFormat::R16G16B16A16_SINT;
case Hash(TextureFormat::R16G16, FLOAT):
return PixelFormat::R16G16_FLOAT;
case Hash(TextureFormat::R16G16, UNORM):
return PixelFormat::R16G16_UNORM;
case Hash(TextureFormat::R16G16, SNORM):
return PixelFormat::R16G16_SNORM;
case Hash(TextureFormat::R16G16, UINT):
return PixelFormat::R16G16_UINT;
case Hash(TextureFormat::R16G16, SINT):
return PixelFormat::R16G16_SINT;
case Hash(TextureFormat::R16, FLOAT):
return PixelFormat::R16_FLOAT;
case Hash(TextureFormat::R16, UNORM):
return PixelFormat::R16_UNORM;
case Hash(TextureFormat::R16, SNORM):
return PixelFormat::R16_SNORM;
case Hash(TextureFormat::R16, UINT):
return PixelFormat::R16_UINT;
case Hash(TextureFormat::R16, SINT):
return PixelFormat::R16_SINT;
case Hash(TextureFormat::B10G11R11, FLOAT):
return PixelFormat::B10G11R11_FLOAT;
case Hash(TextureFormat::R32G32B32A32, FLOAT):
return PixelFormat::R32G32B32A32_FLOAT;
case Hash(TextureFormat::R32G32B32A32, UINT):
return PixelFormat::R32G32B32A32_UINT;
case Hash(TextureFormat::R32G32B32A32, SINT):
return PixelFormat::R32G32B32A32_SINT;
case Hash(TextureFormat::R32G32B32, FLOAT):
return PixelFormat::R32G32B32_FLOAT;
case Hash(TextureFormat::R32G32, FLOAT):
return PixelFormat::R32G32_FLOAT;
case Hash(TextureFormat::R32G32, UINT):
return PixelFormat::R32G32_UINT;
case Hash(TextureFormat::R32G32, SINT):
return PixelFormat::R32G32_SINT;
case Hash(TextureFormat::R32, FLOAT):
return PixelFormat::R32_FLOAT;
case Hash(TextureFormat::R32, UINT):
return PixelFormat::R32_UINT;
case Hash(TextureFormat::R32, SINT):
return PixelFormat::R32_SINT;
case Hash(TextureFormat::E5B9G9R9, FLOAT):
return PixelFormat::E5B9G9R9_FLOAT;
case Hash(TextureFormat::Z32, FLOAT):
return PixelFormat::D32_FLOAT;
case Hash(TextureFormat::Z32, FLOAT, UINT, UINT, UINT, LINEAR):
return PixelFormat::D32_FLOAT;
case Hash(TextureFormat::Z16, UNORM):
return PixelFormat::D16_UNORM;
case Hash(TextureFormat::Z16, UNORM, UINT, UINT, UINT, LINEAR):
return PixelFormat::D16_UNORM;
case Hash(TextureFormat::X8Z24, UNORM):
return PixelFormat::X8_D24_UNORM;
case Hash(TextureFormat::X8Z24, UNORM, UINT, UINT, UINT, LINEAR):
return PixelFormat::X8_D24_UNORM;
case Hash(TextureFormat::Z24S8, UINT, UNORM, UNORM, UNORM, LINEAR):
return PixelFormat::S8_UINT_D24_UNORM;
case Hash(TextureFormat::Z24S8, UINT, UNORM, UINT, UINT, LINEAR):
return PixelFormat::S8_UINT_D24_UNORM;
case Hash(TextureFormat::G24R8, UINT, UNORM, UNORM, UNORM, LINEAR):
return PixelFormat::S8_UINT_D24_UNORM;
case Hash(TextureFormat::S8Z24, UNORM, UINT, UINT, UINT, LINEAR):
return PixelFormat::D24_UNORM_S8_UINT;
case Hash(TextureFormat::Z32_X24S8, FLOAT, UINT, UNORM, UNORM, LINEAR):
return PixelFormat::D32_FLOAT_S8_UINT;
case Hash(TextureFormat::R32B24G8, FLOAT, UINT, UNORM, UNORM, LINEAR):
return PixelFormat::D32_FLOAT_S8_UINT;
case Hash(TextureFormat::DXT1, UNORM, LINEAR):
return PixelFormat::BC1_RGBA_UNORM;
case Hash(TextureFormat::DXT1, UNORM, SRGB):
return PixelFormat::BC1_RGBA_SRGB;
case Hash(TextureFormat::DXT23, UNORM, LINEAR):
return PixelFormat::BC2_UNORM;
case Hash(TextureFormat::DXT23, UNORM, SRGB):
return PixelFormat::BC2_SRGB;
case Hash(TextureFormat::DXT45, UNORM, LINEAR):
return PixelFormat::BC3_UNORM;
case Hash(TextureFormat::DXT45, UNORM, SRGB):
return PixelFormat::BC3_SRGB;
case Hash(TextureFormat::DXN1, UNORM):
return PixelFormat::BC4_UNORM;
case Hash(TextureFormat::DXN1, SNORM):
return PixelFormat::BC4_SNORM;
case Hash(TextureFormat::DXN2, UNORM):
return PixelFormat::BC5_UNORM;
case Hash(TextureFormat::DXN2, SNORM):
return PixelFormat::BC5_SNORM;
case Hash(TextureFormat::BC7U, UNORM, LINEAR):
return PixelFormat::BC7_UNORM;
case Hash(TextureFormat::BC7U, UNORM, SRGB):
return PixelFormat::BC7_SRGB;
case Hash(TextureFormat::BC6H_S16, FLOAT):
return PixelFormat::BC6H_SFLOAT;
case Hash(TextureFormat::BC6H_U16, FLOAT):
return PixelFormat::BC6H_UFLOAT;
case Hash(TextureFormat::ASTC_2D_4X4, UNORM, LINEAR):
return PixelFormat::ASTC_2D_4X4_UNORM;
case Hash(TextureFormat::ASTC_2D_4X4, UNORM, SRGB):
return PixelFormat::ASTC_2D_4X4_SRGB;
case Hash(TextureFormat::ASTC_2D_5X4, UNORM, LINEAR):
return PixelFormat::ASTC_2D_5X4_UNORM;
case Hash(TextureFormat::ASTC_2D_5X4, UNORM, SRGB):
return PixelFormat::ASTC_2D_5X4_SRGB;
case Hash(TextureFormat::ASTC_2D_5X5, UNORM, LINEAR):
return PixelFormat::ASTC_2D_5X5_UNORM;
case Hash(TextureFormat::ASTC_2D_5X5, UNORM, SRGB):
return PixelFormat::ASTC_2D_5X5_SRGB;
case Hash(TextureFormat::ASTC_2D_8X8, UNORM, LINEAR):
return PixelFormat::ASTC_2D_8X8_UNORM;
case Hash(TextureFormat::ASTC_2D_8X8, UNORM, SRGB):
return PixelFormat::ASTC_2D_8X8_SRGB;
case Hash(TextureFormat::ASTC_2D_8X5, UNORM, LINEAR):
return PixelFormat::ASTC_2D_8X5_UNORM;
case Hash(TextureFormat::ASTC_2D_8X5, UNORM, SRGB):
return PixelFormat::ASTC_2D_8X5_SRGB;
case Hash(TextureFormat::ASTC_2D_10X8, UNORM, LINEAR):
return PixelFormat::ASTC_2D_10X8_UNORM;
case Hash(TextureFormat::ASTC_2D_10X8, UNORM, SRGB):
return PixelFormat::ASTC_2D_10X8_SRGB;
case Hash(TextureFormat::ASTC_2D_6X6, UNORM, LINEAR):
return PixelFormat::ASTC_2D_6X6_UNORM;
case Hash(TextureFormat::ASTC_2D_6X6, UNORM, SRGB):
return PixelFormat::ASTC_2D_6X6_SRGB;
case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR):
return PixelFormat::ASTC_2D_10X6_UNORM;
case Hash(TextureFormat::ASTC_2D_10X6, UNORM, SRGB):
return PixelFormat::ASTC_2D_10X6_SRGB;
case Hash(TextureFormat::ASTC_2D_10X5, UNORM, LINEAR):
return PixelFormat::ASTC_2D_10X5_UNORM;
case Hash(TextureFormat::ASTC_2D_10X5, UNORM, SRGB):
return PixelFormat::ASTC_2D_10X5_SRGB;
case Hash(TextureFormat::ASTC_2D_10X10, UNORM, LINEAR):
return PixelFormat::ASTC_2D_10X10_UNORM;
case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB):
return PixelFormat::ASTC_2D_10X10_SRGB;
case Hash(TextureFormat::ASTC_2D_12X10, UNORM, LINEAR):
return PixelFormat::ASTC_2D_12X10_UNORM;
case Hash(TextureFormat::ASTC_2D_12X10, UNORM, SRGB):
return PixelFormat::ASTC_2D_12X10_SRGB;
case Hash(TextureFormat::ASTC_2D_12X12, UNORM, LINEAR):
return PixelFormat::ASTC_2D_12X12_UNORM;
case Hash(TextureFormat::ASTC_2D_12X12, UNORM, SRGB):
return PixelFormat::ASTC_2D_12X12_SRGB;
case Hash(TextureFormat::ASTC_2D_8X6, UNORM, LINEAR):
return PixelFormat::ASTC_2D_8X6_UNORM;
case Hash(TextureFormat::ASTC_2D_8X6, UNORM, SRGB):
return PixelFormat::ASTC_2D_8X6_SRGB;
case Hash(TextureFormat::ASTC_2D_6X5, UNORM, LINEAR):
return PixelFormat::ASTC_2D_6X5_UNORM;
case Hash(TextureFormat::ASTC_2D_6X5, UNORM, SRGB):
return PixelFormat::ASTC_2D_6X5_SRGB;
}
UNIMPLEMENTED_MSG("texture format={} srgb={} components={{{} {} {} {}}}",
static_cast<int>(format), is_srgb, static_cast<int>(red),
static_cast<int>(green), static_cast<int>(blue), static_cast<int>(alpha));
PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red, ComponentType green, ComponentType blue, ComponentType alpha, bool is_srgb) noexcept {
if (false) { /* no op */ }
#define TF2PF_ELEM(FMT, CR, CG, CB, CA, SRGB, RES) \
else if (format == TextureFormat::FMT \
&& red == ComponentType::CR && green == ComponentType::CG \
&& blue == ComponentType::CB && alpha == ComponentType::CA \
&& is_srgb == SRGB) return PixelFormat::RES;
TF2PF_LIST
#undef TF2PF_ELEM
UNIMPLEMENTED_MSG("texture format={} srgb={} components={{{} {} {} {}}}", int(format), is_srgb, int(red), int(green), int(blue), int(alpha));
return PixelFormat::A8B8G8R8_UNORM;
}