aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/engines/fermi_2d.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp102
-rw-r--r--src/video_core/engines/maxwell_3d.h29
-rw-r--r--src/video_core/engines/shader_bytecode.h8
-rw-r--r--src/video_core/gpu.cpp1
-rw-r--r--src/video_core/gpu.h1
-rw-r--r--src/video_core/macro_interpreter.cpp2
-rw-r--r--src/video_core/morton.cpp2
-rw-r--r--src/video_core/rasterizer_interface.h9
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp22
-rw-r--r--src/video_core/renderer_opengl/gl_device.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp181
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h9
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp184
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp22
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp15
-rw-r--r--src/video_core/shader/decode/image.cpp137
-rw-r--r--src/video_core/shader/node.h46
-rw-r--r--src/video_core/shader/shader_ir.cpp12
-rw-r--r--src/video_core/shader/shader_ir.h19
-rw-r--r--src/video_core/surface.cpp3
-rw-r--r--src/video_core/surface.h50
26 files changed, 524 insertions, 358 deletions
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 98a8b5337..7ff44f06d 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -29,8 +29,8 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
}
void Fermi2D::HandleSurfaceCopy() {
- LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}",
- static_cast<u32>(regs.operation));
+ LOG_DEBUG(HW_GPU, "Requested a surface copy with operation {}",
+ static_cast<u32>(regs.operation));
// TODO(Subv): Only raw copies are implemented.
ASSERT(regs.operation == Operation::SrcCopy);
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index fb3d1112c..b318aedb8 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -92,6 +92,10 @@ void Maxwell3D::InitializeRegisterDefaults() {
// Some games (like Super Mario Odyssey) assume that SRGB is enabled.
regs.framebuffer_srgb = 1;
+ mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true;
+ mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true;
+ mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
+ mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
}
#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
@@ -256,6 +260,9 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3
// Execute the current macro.
macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
+ if (mme_draw.current_mode != MMEDrawMode::Undefined) {
+ FlushMMEInlineDraw();
+ }
}
void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
@@ -416,6 +423,97 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
}
}
+void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
+ if (mme_draw.current_mode == MMEDrawMode::Undefined) {
+ if (mme_draw.gl_begin_consume) {
+ mme_draw.current_mode = expected_mode;
+ mme_draw.current_count = count;
+ mme_draw.instance_count = 1;
+ mme_draw.gl_begin_consume = false;
+ mme_draw.gl_end_count = 0;
+ }
+ return;
+ } else {
+ if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count &&
+ mme_draw.instance_mode && mme_draw.gl_begin_consume) {
+ mme_draw.instance_count++;
+ mme_draw.gl_begin_consume = false;
+ return;
+ } else {
+ FlushMMEInlineDraw();
+ }
+ }
+ // Tail call in case it needs to retry.
+ StepInstance(expected_mode, count);
+}
+
+void Maxwell3D::CallMethodFromMME(const GPU::MethodCall& method_call) {
+ const u32 method = method_call.method;
+ if (mme_inline[method]) {
+ regs.reg_array[method] = method_call.argument;
+ if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) ||
+ method == MAXWELL3D_REG_INDEX(index_array.count)) {
+ const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count)
+ ? MMEDrawMode::Array
+ : MMEDrawMode::Indexed;
+ StepInstance(expected_mode, method_call.argument);
+ } else if (method == MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)) {
+ mme_draw.instance_mode =
+ (regs.draw.instance_next != 0) || (regs.draw.instance_cont != 0);
+ mme_draw.gl_begin_consume = true;
+ } else {
+ mme_draw.gl_end_count++;
+ }
+ } else {
+ if (mme_draw.current_mode != MMEDrawMode::Undefined) {
+ FlushMMEInlineDraw();
+ }
+ CallMethod(method_call);
+ }
+}
+
+void Maxwell3D::FlushMMEInlineDraw() {
+ LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
+ regs.vertex_buffer.count);
+ ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
+ ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
+
+ auto debug_context = system.GetGPUDebugContext();
+
+ if (debug_context) {
+ debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
+ }
+
+ // Both instance configuration registers can not be set at the same time.
+ ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
+ "Illegal combination of instancing parameters");
+
+ const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;
+ if (ShouldExecute()) {
+ rasterizer.DrawMultiBatch(is_indexed);
+ }
+
+ if (debug_context) {
+ debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
+ }
+
+ // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
+ // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
+ // it's possible that it is incorrect and that there is some other register used to specify the
+ // drawing mode.
+ if (is_indexed) {
+ regs.index_array.count = 0;
+ } else {
+ regs.vertex_buffer.count = 0;
+ }
+ mme_draw.current_mode = MMEDrawMode::Undefined;
+ mme_draw.current_count = 0;
+ mme_draw.instance_count = 0;
+ mme_draw.instance_mode = false;
+ mme_draw.gl_begin_consume = false;
+ mme_draw.gl_end_count = 0;
+}
+
void Maxwell3D::ProcessMacroUpload(u32 data) {
ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
"upload_address exceeded macro_memory size!");
@@ -564,7 +662,9 @@ void Maxwell3D::DrawArrays() {
}
const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
- rasterizer.AccelerateDrawBatch(is_indexed);
+ if (ShouldExecute()) {
+ rasterizer.DrawBatch(is_indexed);
+ }
if (debug_context) {
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index e5ec90717..4c97759ed 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -811,8 +811,9 @@ public:
INSERT_PADDING_WORDS(0x21);
u32 vb_element_base;
+ u32 vb_base_instance;
- INSERT_PADDING_WORDS(0x36);
+ INSERT_PADDING_WORDS(0x35);
union {
BitField<0, 1, u32> c0;
@@ -1238,6 +1239,11 @@ public:
/// Write the value to the register identified by method.
void CallMethod(const GPU::MethodCall& method_call);
+ /// Write the value to the register identified by method.
+ void CallMethodFromMME(const GPU::MethodCall& method_call);
+
+ void FlushMMEInlineDraw();
+
/// Given a Texture Handle, returns the TSC and TIC entries.
Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
std::size_t offset) const;
@@ -1263,6 +1269,21 @@ public:
return execute_on;
}
+ enum class MMEDrawMode : u32 {
+ Undefined,
+ Array,
+ Indexed,
+ };
+
+ struct MMEDrawState {
+ MMEDrawMode current_mode{MMEDrawMode::Undefined};
+ u32 current_count{};
+ u32 instance_count{};
+ bool instance_mode{};
+ bool gl_begin_consume{};
+ u32 gl_end_count{};
+ } mme_draw;
+
private:
void InitializeRegisterDefaults();
@@ -1275,6 +1296,8 @@ private:
/// Start offsets of each macro in macro_memory
std::array<u32, 0x80> macro_positions = {};
+ std::array<bool, Regs::NUM_REGS> mme_inline{};
+
/// Memory for macro code
MacroMemory macro_memory;
@@ -1346,6 +1369,9 @@ private:
/// Handles a write to the VERTEX_END_GL register, triggering a draw.
void DrawArrays();
+
+ // Handles a instance drawcall from MME
+ void StepInstance(MMEDrawMode expected_mode, u32 count);
};
#define ASSERT_REG_POSITION(field_name, position) \
@@ -1402,6 +1428,7 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
+ASSERT_REG_POSITION(vb_base_instance, 0x50E);
ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 28272ef6f..7a6355ce2 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -544,7 +544,7 @@ enum class VoteOperation : u64 {
Eq = 2, // allThreadsEqualNV
};
-enum class ImageAtomicSize : u64 {
+enum class ImageAtomicOperationType : u64 {
U32 = 0,
S32 = 1,
U64 = 2,
@@ -1432,11 +1432,11 @@ union Instruction {
ASSERT(mode == SurfaceDataMode::D_BA);
return store_data_layout;
}
- } sust;
+ } suldst;
union {
BitField<28, 1, u64> is_ba;
- BitField<51, 3, ImageAtomicSize> size;
+ BitField<51, 3, ImageAtomicOperationType> operation_type;
BitField<33, 3, ImageType> image_type;
BitField<29, 4, ImageAtomicOperation> operation;
BitField<49, 2, OutOfBoundsStore> out_of_bounds_store;
@@ -1595,6 +1595,7 @@ public:
TMML_B, // Texture Mip Map Level
TMML, // Texture Mip Map Level
SUST, // Surface Store
+ SULD, // Surface Load
SUATOM, // Surface Atomic Operation
EXIT,
NOP,
@@ -1884,6 +1885,7 @@ private:
INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"),
INST("1101111101011---", Id::TMML, Type::Texture, "TMML"),
INST("11101011001-----", Id::SUST, Type::Image, "SUST"),
+ INST("11101011000-----", Id::SULD, Type::Image, "SULD"),
INST("1110101000------", Id::SUATOM, Type::Image, "SUATOM_D"),
INST("0101000010110---", Id::NOP, Type::Trivial, "NOP"),
INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 2c47541cb..76cfe8107 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -122,6 +122,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
case RenderTargetFormat::RGBA16_UINT:
case RenderTargetFormat::RGBA16_UNORM:
case RenderTargetFormat::RGBA16_FLOAT:
+ case RenderTargetFormat::RGBX16_FLOAT:
case RenderTargetFormat::RG32_FLOAT:
case RenderTargetFormat::RG32_UINT:
return 8;
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 78bc0601a..29fa8e95b 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -42,6 +42,7 @@ enum class RenderTargetFormat : u32 {
RGBA16_FLOAT = 0xCA,
RG32_FLOAT = 0xCB,
RG32_UINT = 0xCD,
+ RGBX16_FLOAT = 0xCE,
BGRA8_UNORM = 0xCF,
BGRA8_SRGB = 0xD0,
RGB10_A2_UNORM = 0xD1,
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 62afc0d11..dbaeac6db 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -257,7 +257,7 @@ void MacroInterpreter::SetMethodAddress(u32 address) {
}
void MacroInterpreter::Send(u32 value) {
- maxwell3d.CallMethod({method_address.address, value});
+ maxwell3d.CallMethodFromMME({method_address.address, value});
// Increment the method address by the method increment.
method_address.address.Assign(method_address.address.Value() +
method_address.increment.Value());
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp
index 084f85e67..ab71870ab 100644
--- a/src/video_core/morton.cpp
+++ b/src/video_core/morton.cpp
@@ -83,6 +83,7 @@ static constexpr ConversionArray morton_to_linear_fns = {
MortonCopy<true, PixelFormat::RG8U>,
MortonCopy<true, PixelFormat::RG8S>,
MortonCopy<true, PixelFormat::RG32UI>,
+ MortonCopy<true, PixelFormat::RGBX16F>,
MortonCopy<true, PixelFormat::R32UI>,
MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
MortonCopy<true, PixelFormat::ASTC_2D_8X5>,
@@ -151,6 +152,7 @@ static constexpr ConversionArray linear_to_morton_fns = {
MortonCopy<false, PixelFormat::RG8U>,
MortonCopy<false, PixelFormat::RG8S>,
MortonCopy<false, PixelFormat::RG32UI>,
+ MortonCopy<false, PixelFormat::RGBX16F>,
MortonCopy<false, PixelFormat::R32UI>,
nullptr,
nullptr,
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 6b3f2d50a..5b0eca9e2 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -29,7 +29,10 @@ public:
virtual ~RasterizerInterface() {}
/// Draw the current batch of vertex arrays
- virtual void DrawArrays() = 0;
+ virtual bool DrawBatch(bool is_indexed) = 0;
+
+ /// Draw the current batch of multiple instances of vertex arrays
+ virtual bool DrawMultiBatch(bool is_indexed) = 0;
/// Clear the current framebuffer
virtual void Clear() = 0;
@@ -69,10 +72,6 @@ public:
return false;
}
- virtual bool AccelerateDrawBatch(bool is_indexed) {
- return false;
- }
-
/// Increase/decrease the number of object in pages touching the specified region
virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 4f59a87b4..64de7e425 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -2,8 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <array>
#include <cstddef>
+#include <vector>
#include <glad/glad.h>
#include "common/logging/log.h"
@@ -30,9 +32,27 @@ bool TestProgram(const GLchar* glsl) {
return link_status == GL_TRUE;
}
+std::vector<std::string_view> GetExtensions() {
+ GLint num_extensions;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
+ std::vector<std::string_view> extensions;
+ extensions.reserve(num_extensions);
+ for (GLint index = 0; index < num_extensions; ++index) {
+ extensions.push_back(
+ reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index))));
+ }
+ return extensions;
+}
+
+bool HasExtension(const std::vector<std::string_view>& images, std::string_view extension) {
+ return std::find(images.begin(), images.end(), extension) != images.end();
+}
+
} // Anonymous namespace
Device::Device() {
+ const std::vector extensions = GetExtensions();
+
uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
@@ -40,6 +60,7 @@ Device::Device() {
has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
GLAD_GL_NV_shader_thread_shuffle;
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
+ has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
has_variable_aoffi = TestVariableAoffi();
has_component_indexing_bug = TestComponentIndexingBug();
has_precise_bug = TestPreciseBug();
@@ -55,6 +76,7 @@ Device::Device(std::nullptr_t) {
max_varyings = 15;
has_warp_intrinsics = true;
has_vertex_viewport_layer = true;
+ has_image_load_formatted = true;
has_variable_aoffi = true;
has_component_indexing_bug = false;
has_precise_bug = false;
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index ba6dcd3be..bb273c3d6 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -38,6 +38,10 @@ public:
return has_vertex_viewport_layer;
}
+ bool HasImageLoadFormatted() const {
+ return has_image_load_formatted;
+ }
+
bool HasVariableAoffi() const {
return has_variable_aoffi;
}
@@ -61,6 +65,7 @@ private:
u32 max_varyings{};
bool has_warp_intrinsics{};
bool has_vertex_viewport_layer{};
+ bool has_image_load_formatted{};
bool has_variable_aoffi{};
bool has_component_indexing_bug{};
bool has_precise_bug{};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a2c1473db..6a17bed72 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -49,40 +49,6 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100));
-struct DrawParameters {
- GLenum primitive_mode;
- GLsizei count;
- GLint current_instance;
- bool use_indexed;
-
- GLint vertex_first;
-
- GLenum index_format;
- GLint base_vertex;
- GLintptr index_buffer_offset;
-
- void DispatchDraw() const {
- if (use_indexed) {
- const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
- if (current_instance > 0) {
- glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
- index_buffer_ptr, 1, base_vertex,
- current_instance);
- } else {
- glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
- base_vertex);
- }
- } else {
- if (current_instance > 0) {
- glDrawArraysInstancedBaseInstance(primitive_mode, vertex_first, count, 1,
- current_instance);
- } else {
- glDrawArrays(primitive_mode, vertex_first, count);
- }
- }
- }
-};
-
static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
const GLShader::ConstBufferEntry& entry) {
if (!entry.IsIndirect()) {
@@ -270,29 +236,6 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
return offset;
}
-DrawParameters RasterizerOpenGL::SetupDraw(GLintptr index_buffer_offset) {
- const auto& gpu = system.GPU().Maxwell3D();
- const auto& regs = gpu.regs;
- const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
-
- DrawParameters params{};
- params.current_instance = gpu.state.current_instance;
-
- params.use_indexed = is_indexed;
- params.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
-
- if (is_indexed) {
- params.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
- params.count = regs.index_array.count;
- params.index_buffer_offset = index_buffer_offset;
- params.base_vertex = static_cast<GLint>(regs.vb_element_base);
- } else {
- params.count = regs.vertex_buffer.count;
- params.vertex_first = regs.vertex_buffer.first;
- }
- return params;
-}
-
void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
MICROPROFILE_SCOPE(OpenGL_Shader);
auto& gpu = system.GPU().Maxwell3D();
@@ -399,12 +342,6 @@ std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const {
static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
}
-bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
- accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
- DrawArrays();
- return true;
-}
-
template <typename Map, typename Interval>
static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
return boost::make_iterator_range(map.equal_range(interval));
@@ -640,17 +577,9 @@ void RasterizerOpenGL::Clear() {
}
}
-void RasterizerOpenGL::DrawArrays() {
- if (accelerate_draw == AccelDraw::Disabled)
- return;
-
- MICROPROFILE_SCOPE(OpenGL_Drawing);
+void RasterizerOpenGL::DrawPrelude() {
auto& gpu = system.GPU().Maxwell3D();
- if (!gpu.ShouldExecute()) {
- return;
- }
-
SyncColorMask();
SyncFragmentColorClampState();
SyncMultiSampleState();
@@ -695,10 +624,7 @@ void RasterizerOpenGL::DrawArrays() {
// Upload vertex and index data.
SetupVertexBuffer(vao);
SetupVertexInstances(vao);
- const GLintptr index_buffer_offset = SetupIndexBuffer();
-
- // Setup draw parameters. It will automatically choose what glDraw* method to use.
- const DrawParameters params = SetupDraw(index_buffer_offset);
+ index_buffer_offset = SetupIndexBuffer();
// Prepare packed bindings.
bind_ubo_pushbuffer.Setup(0);
@@ -706,7 +632,8 @@ void RasterizerOpenGL::DrawArrays() {
// Setup shaders and their used resources.
texture_cache.GuardSamplers(true);
- SetupShaders(params.primitive_mode);
+ const auto primitive_mode = MaxwellToGL::PrimitiveTopology(gpu.regs.draw.topology);
+ SetupShaders(primitive_mode);
texture_cache.GuardSamplers(false);
ConfigureFramebuffers();
@@ -730,11 +657,107 @@ void RasterizerOpenGL::DrawArrays() {
if (texture_cache.TextureBarrier()) {
glTextureBarrier();
}
+}
+
+struct DrawParams {
+ bool is_indexed{};
+ bool is_instanced{};
+ GLenum primitive_mode{};
+ GLint count{};
+ GLint base_vertex{};
+
+ // Indexed settings
+ GLenum index_format{};
+ GLintptr index_buffer_offset{};
+
+ // Instanced setting
+ GLint num_instances{};
+ GLint base_instance{};
+
+ void DispatchDraw() {
+ if (is_indexed) {
+ const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
+ if (is_instanced) {
+ glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
+ index_buffer_ptr, num_instances,
+ base_vertex, base_instance);
+ } else {
+ glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
+ base_vertex);
+ }
+ } else {
+ if (is_instanced) {
+ glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, count, num_instances,
+ base_instance);
+ } else {
+ glDrawArrays(primitive_mode, base_vertex, count);
+ }
+ }
+ }
+};
- params.DispatchDraw();
+bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
+ accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
+
+ MICROPROFILE_SCOPE(OpenGL_Drawing);
+ DrawPrelude();
+
+ auto& maxwell3d = system.GPU().Maxwell3D();
+ const auto& regs = maxwell3d.regs;
+ const auto current_instance = maxwell3d.state.current_instance;
+ DrawParams draw_call{};
+ draw_call.is_indexed = is_indexed;
+ draw_call.num_instances = static_cast<GLint>(1);
+ draw_call.base_instance = static_cast<GLint>(current_instance);
+ draw_call.is_instanced = current_instance > 0;
+ draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
+ if (draw_call.is_indexed) {
+ draw_call.count = static_cast<GLint>(regs.index_array.count);
+ draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
+ draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
+ draw_call.index_buffer_offset = index_buffer_offset;
+ } else {
+ draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
+ draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
+ }
+ draw_call.DispatchDraw();
+
+ maxwell3d.dirty.memory_general = false;
accelerate_draw = AccelDraw::Disabled;
- gpu.dirty.memory_general = false;
+ return true;
+}
+
+bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) {
+ accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
+
+ MICROPROFILE_SCOPE(OpenGL_Drawing);
+
+ DrawPrelude();
+
+ auto& maxwell3d = system.GPU().Maxwell3D();
+ const auto& regs = maxwell3d.regs;
+ const auto& draw_setup = maxwell3d.mme_draw;
+ DrawParams draw_call{};
+ draw_call.is_indexed = is_indexed;
+ draw_call.num_instances = static_cast<GLint>(draw_setup.instance_count);
+ draw_call.base_instance = static_cast<GLint>(regs.vb_base_instance);
+ draw_call.is_instanced = draw_setup.instance_count > 1;
+ draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
+ if (draw_call.is_indexed) {
+ draw_call.count = static_cast<GLint>(regs.index_array.count);
+ draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
+ draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
+ draw_call.index_buffer_offset = index_buffer_offset;
+ } else {
+ draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
+ draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
+ }
+ draw_call.DispatchDraw();
+
+ maxwell3d.dirty.memory_general = false;
+ accelerate_draw = AccelDraw::Disabled;
+ return true;
}
void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 4f5c7f864..9c10ebda3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -57,7 +57,8 @@ public:
ScreenInfo& info);
~RasterizerOpenGL() override;
- void DrawArrays() override;
+ bool DrawBatch(bool is_indexed) override;
+ bool DrawMultiBatch(bool is_indexed) override;
void Clear() override;
void DispatchCompute(GPUVAddr code_addr) override;
void FlushAll() override;
@@ -71,7 +72,6 @@ public:
const Tegra::Engines::Fermi2D::Config& copy_config) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
- bool AccelerateDrawBatch(bool is_indexed) override;
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
void LoadDiskResources(const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) override;
@@ -105,6 +105,9 @@ private:
void SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entry, GPUVAddr gpu_addr,
std::size_t size);
+ /// Syncs all the state, shaders, render targets and textures setting before a draw call.
+ void DrawPrelude();
+
/// Configures the current textures to use for the draw command. Returns shaders texture buffer
/// usage.
TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
@@ -216,7 +219,7 @@ private:
GLintptr SetupIndexBuffer();
- DrawParameters SetupDraw(GLintptr index_buffer_offset);
+ GLintptr index_buffer_offset;
void SetupShaders(GLenum primitive_mode);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 0dbc4c02f..42ca3b1bd 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -211,14 +211,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn
const auto primitive_mode{variant.primitive_mode};
const auto texture_buffer_usage{variant.texture_buffer_usage};
- std::string source = "#version 430 core\n"
- "#extension GL_ARB_separate_shader_objects : enable\n"
- "#extension GL_NV_gpu_shader5 : enable\n"
- "#extension GL_NV_shader_thread_group : enable\n"
- "#extension GL_NV_shader_thread_shuffle : enable\n";
- if (entries.shader_viewport_layer_array) {
- source += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
- }
+ std::string source = R"(#version 430 core
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shader_viewport_layer_array : enable
+#extension GL_EXT_shader_image_load_formatted : enable
+#extension GL_NV_gpu_shader5 : enable
+#extension GL_NV_shader_thread_group : enable
+#extension GL_NV_shader_thread_shuffle : enable
+)";
if (program_type == ProgramType::Compute) {
source += "#extension GL_ARB_compute_variable_group_size : require\n";
}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 76439e7ab..8fa9e6534 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -19,6 +19,7 @@
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
+#include "video_core/shader/node.h"
#include "video_core/shader/shader_ir.h"
namespace OpenGL::GLShader {
@@ -241,6 +242,26 @@ constexpr const char* GetTypeString(Type type) {
}
}
+constexpr const char* GetImageTypeDeclaration(Tegra::Shader::ImageType image_type) {
+ switch (image_type) {
+ case Tegra::Shader::ImageType::Texture1D:
+ return "1D";
+ case Tegra::Shader::ImageType::TextureBuffer:
+ return "Buffer";
+ case Tegra::Shader::ImageType::Texture1DArray:
+ return "1DArray";
+ case Tegra::Shader::ImageType::Texture2D:
+ return "2D";
+ case Tegra::Shader::ImageType::Texture2DArray:
+ return "2DArray";
+ case Tegra::Shader::ImageType::Texture3D:
+ return "3D";
+ default:
+ UNREACHABLE();
+ return "1D";
+ }
+}
+
/// Generates code to use for a swizzle operation.
constexpr const char* GetSwizzle(u32 element) {
constexpr std::array swizzle = {".x", ".y", ".z", ".w"};
@@ -398,8 +419,6 @@ public:
usage.is_read, usage.is_written);
}
entries.clip_distances = ir.GetClipDistances();
- entries.shader_viewport_layer_array =
- IsVertexShader(stage) && (ir.UsesLayer() || ir.UsesViewportIndex());
entries.shader_length = ir.GetLength();
return entries;
}
@@ -462,6 +481,14 @@ private:
code.AddLine("float gl_PointSize;");
}
+ if (ir.UsesInstanceId()) {
+ code.AddLine("int gl_InstanceID;");
+ }
+
+ if (ir.UsesVertexId()) {
+ code.AddLine("int gl_VertexID;");
+ }
+
--code.scope;
code.AddLine("}};");
code.AddNewLine();
@@ -714,42 +741,6 @@ private:
void DeclareImages() {
const auto& images{ir.GetImages()};
for (const auto& [offset, image] : images) {
- const char* image_type = [&] {
- switch (image.GetType()) {
- case Tegra::Shader::ImageType::Texture1D:
- return "image1D";
- case Tegra::Shader::ImageType::TextureBuffer:
- return "imageBuffer";
- case Tegra::Shader::ImageType::Texture1DArray:
- return "image1DArray";
- case Tegra::Shader::ImageType::Texture2D:
- return "image2D";
- case Tegra::Shader::ImageType::Texture2DArray:
- return "image2DArray";
- case Tegra::Shader::ImageType::Texture3D:
- return "image3D";
- default:
- UNREACHABLE();
- return "image1D";
- }
- }();
-
- const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> {
- if (!image.IsSizeKnown()) {
- return {"", ""};
- }
- switch (image.GetSize()) {
- case Tegra::Shader::ImageAtomicSize::U32:
- return {"u", "r32ui, "};
- case Tegra::Shader::ImageAtomicSize::S32:
- return {"i", "r32i, "};
- default:
- UNIMPLEMENTED_MSG("Unimplemented atomic size={}",
- static_cast<u32>(image.GetSize()));
- return {"", ""};
- }
- }();
-
std::string qualifier = "coherent volatile";
if (image.IsRead() && !image.IsWritten()) {
qualifier += " readonly";
@@ -757,9 +748,10 @@ private:
qualifier += " writeonly";
}
- code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform "
- "{} {};",
- image.GetIndex(), qualifier, image_type, GetImage(image));
+ const char* format = image.IsAtomic() ? "r32ui, " : "";
+ const char* type_declaration = GetImageTypeDeclaration(image.GetType());
+ code.AddLine("layout ({}binding = IMAGE_BINDING_{}) {} uniform uimage{} {};", format,
+ image.GetIndex(), qualifier, type_declaration, GetImage(image));
}
if (!images.empty()) {
code.AddNewLine();
@@ -964,7 +956,7 @@ private:
switch (element) {
case 2:
// Config pack's first value is instance_id.
- return {"config_pack[0]", Type::Uint};
+ return {"gl_InstanceID", Type::Int};
case 3:
return {"gl_VertexID", Type::Int};
}
@@ -1226,28 +1218,13 @@ private:
}
std::string BuildImageValues(Operation operation) {
+ constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"};
const auto meta{std::get<MetaImage>(operation.GetMeta())};
- const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> {
- constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"};
- if (!meta.image.IsSizeKnown()) {
- return {float_constructors, Type::Float};
- }
- switch (meta.image.GetSize()) {
- case Tegra::Shader::ImageAtomicSize::U32:
- return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint};
- case Tegra::Shader::ImageAtomicSize::S32:
- return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint};
- default:
- UNIMPLEMENTED_MSG("Unimplemented image size={}",
- static_cast<u32>(meta.image.GetSize()));
- return {float_constructors, Type::Float};
- }
- }();
const std::size_t values_count{meta.values.size()};
std::string expr = fmt::format("{}(", constructors.at(values_count - 1));
for (std::size_t i = 0; i < values_count; ++i) {
- expr += Visit(meta.values.at(i)).As(type);
+ expr += Visit(meta.values.at(i)).AsUint();
if (i + 1 < values_count) {
expr += ", ";
}
@@ -1256,29 +1233,6 @@ private:
return expr;
}
- Expression AtomicImage(Operation operation, const char* opname) {
- constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
- const auto meta{std::get<MetaImage>(operation.GetMeta())};
- ASSERT(meta.values.size() == 1);
- ASSERT(meta.image.IsSizeKnown());
-
- const auto type = [&]() {
- switch (const auto size = meta.image.GetSize()) {
- case Tegra::Shader::ImageAtomicSize::U32:
- return Type::Uint;
- case Tegra::Shader::ImageAtomicSize::S32:
- return Type::Int;
- default:
- UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size));
- return Type::Uint;
- }
- }();
-
- return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image),
- BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)),
- type};
- }
-
Expression Assign(Operation operation) {
const Node& dest = operation[0];
const Node& src = operation[1];
@@ -1537,6 +1491,8 @@ private:
case Tegra::Shader::HalfType::H1_H1:
return {fmt::format("vec2({}[1])", operand.AsHalfFloat()), Type::HalfFloat};
}
+ UNREACHABLE();
+ return {"0", Type::Int};
}
Expression HMergeF32(Operation operation) {
@@ -1801,6 +1757,19 @@ private:
return {tmp, Type::Float};
}
+ Expression ImageLoad(Operation operation) {
+ if (!device.HasImageLoadFormatted()) {
+ LOG_ERROR(Render_OpenGL,
+ "Device lacks GL_EXT_shader_image_load_formatted, stubbing image load");
+ return {"0", Type::Int};
+ }
+
+ const auto meta{std::get<MetaImage>(operation.GetMeta())};
+ return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image),
+ BuildIntegerCoordinates(operation), GetSwizzle(meta.element)),
+ Type::Uint};
+ }
+
Expression ImageStore(Operation operation) {
const auto meta{std::get<MetaImage>(operation.GetMeta())};
code.AddLine("imageStore({}, {}, {});", GetImage(meta.image),
@@ -1808,31 +1777,14 @@ private:
return {};
}
- Expression AtomicImageAdd(Operation operation) {
- return AtomicImage(operation, "imageAtomicAdd");
- }
-
- Expression AtomicImageMin(Operation operation) {
- return AtomicImage(operation, "imageAtomicMin");
- }
-
- Expression AtomicImageMax(Operation operation) {
- return AtomicImage(operation, "imageAtomicMax");
- }
- Expression AtomicImageAnd(Operation operation) {
- return AtomicImage(operation, "imageAtomicAnd");
- }
-
- Expression AtomicImageOr(Operation operation) {
- return AtomicImage(operation, "imageAtomicOr");
- }
-
- Expression AtomicImageXor(Operation operation) {
- return AtomicImage(operation, "imageAtomicXor");
- }
+ template <const std::string_view& opname>
+ Expression AtomicImage(Operation operation) {
+ const auto meta{std::get<MetaImage>(operation.GetMeta())};
+ ASSERT(meta.values.size() == 1);
- Expression AtomicImageExchange(Operation operation) {
- return AtomicImage(operation, "imageAtomicExchange");
+ return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image),
+ BuildIntegerCoordinates(operation), Visit(meta.values[0]).AsUint()),
+ Type::Uint};
}
Expression Branch(Operation operation) {
@@ -2027,6 +1979,12 @@ private:
Func() = delete;
~Func() = delete;
+ static constexpr std::string_view Add = "Add";
+ static constexpr std::string_view And = "And";
+ static constexpr std::string_view Or = "Or";
+ static constexpr std::string_view Xor = "Xor";
+ static constexpr std::string_view Exchange = "Exchange";
+
static constexpr std::string_view ShuffleIndexed = "shuffleNV";
static constexpr std::string_view ShuffleUp = "shuffleUpNV";
static constexpr std::string_view ShuffleDown = "shuffleDownNV";
@@ -2164,14 +2122,14 @@ private:
&GLSLDecompiler::TextureQueryLod,
&GLSLDecompiler::TexelFetch,
+ &GLSLDecompiler::ImageLoad,
&GLSLDecompiler::ImageStore,
- &GLSLDecompiler::AtomicImageAdd,
- &GLSLDecompiler::AtomicImageMin,
- &GLSLDecompiler::AtomicImageMax,
- &GLSLDecompiler::AtomicImageAnd,
- &GLSLDecompiler::AtomicImageOr,
- &GLSLDecompiler::AtomicImageXor,
- &GLSLDecompiler::AtomicImageExchange,
+
+ &GLSLDecompiler::AtomicImage<Func::Add>,
+ &GLSLDecompiler::AtomicImage<Func::And>,
+ &GLSLDecompiler::AtomicImage<Func::Or>,
+ &GLSLDecompiler::AtomicImage<Func::Xor>,
+ &GLSLDecompiler::AtomicImage<Func::Exchange>,
&GLSLDecompiler::Branch,
&GLSLDecompiler::BranchIndirect,
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 2ea02f5bf..e538dc001 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -90,7 +90,6 @@ struct ShaderEntries {
std::vector<ImageEntry> images;
std::vector<GlobalMemoryEntry> global_memory_entries;
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
- bool shader_viewport_layer_array{};
std::size_t shader_length{};
};
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index f141c4e3b..6a7012b54 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -343,20 +343,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
u8 is_bindless{};
u8 is_written{};
u8 is_read{};
- u8 is_size_known{};
- u32 size{};
+ u8 is_atomic{};
if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
!LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
!LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) ||
- !LoadObjectFromPrecompiled(is_size_known) || !LoadObjectFromPrecompiled(size)) {
+ !LoadObjectFromPrecompiled(is_atomic)) {
return {};
}
entry.entries.images.emplace_back(
static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0,
- is_read != 0,
- is_size_known ? std::make_optional(static_cast<Tegra::Shader::ImageAtomicSize>(size))
- : std::nullopt);
+ is_read != 0, is_atomic != 0);
}
u32 global_memory_count{};
@@ -382,12 +379,6 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
}
}
- bool shader_viewport_layer_array{};
- if (!LoadObjectFromPrecompiled(shader_viewport_layer_array)) {
- return {};
- }
- entry.entries.shader_viewport_layer_array = shader_viewport_layer_array;
-
u64 shader_length{};
if (!LoadObjectFromPrecompiled(shader_length)) {
return {};
@@ -435,14 +426,13 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
return false;
}
for (const auto& image : entries.images) {
- const u32 size = image.IsSizeKnown() ? static_cast<u32>(image.GetSize()) : 0U;
if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
!SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
!SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) ||
- !SaveObjectToPrecompiled(image.IsSizeKnown()) || !SaveObjectToPrecompiled(size)) {
+ !SaveObjectToPrecompiled(static_cast<u8>(image.IsAtomic() ? 1 : 0))) {
return false;
}
}
@@ -464,10 +454,6 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
}
}
- if (!SaveObjectToPrecompiled(entries.shader_viewport_layer_array)) {
- return false;
- }
-
if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) {
return false;
}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 4f135fe03..173b76c4e 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -97,6 +97,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U
{GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
{GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI
+ {GL_RGB16F, GL_RGBA16, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBX16F
{GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 0bbbf6851..3c5acda3e 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -143,6 +143,7 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
{vk::Format::eUndefined, ComponentType::Invalid, false}, // RG8U
{vk::Format::eUndefined, ComponentType::Invalid, false}, // RG8S
{vk::Format::eUndefined, ComponentType::Invalid, false}, // RG32UI
+ {vk::Format::eUndefined, ComponentType::Invalid, false}, // RGBX16F
{vk::Format::eUndefined, ComponentType::Invalid, false}, // R32UI
{vk::Format::eUndefined, ComponentType::Invalid, false}, // ASTC_2D_8X8
{vk::Format::eUndefined, ComponentType::Invalid, false}, // ASTC_2D_8X5
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index f7fbbb6e4..77fc58f25 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -19,6 +19,7 @@
#include "video_core/engines/shader_header.h"
#include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
+#include "video_core/shader/node.h"
#include "video_core/shader/shader_ir.h"
namespace Vulkan::VKShader {
@@ -939,22 +940,17 @@ private:
return {};
}
- Id ImageStore(Operation operation) {
- UNIMPLEMENTED();
- return {};
- }
-
- Id AtomicImageAdd(Operation operation) {
+ Id ImageLoad(Operation operation) {
UNIMPLEMENTED();
return {};
}
- Id AtomicImageMin(Operation operation) {
+ Id ImageStore(Operation operation) {
UNIMPLEMENTED();
return {};
}
- Id AtomicImageMax(Operation operation) {
+ Id AtomicImageAdd(Operation operation) {
UNIMPLEMENTED();
return {};
}
@@ -1440,10 +1436,9 @@ private:
&SPIRVDecompiler::TextureQueryLod,
&SPIRVDecompiler::TexelFetch,
+ &SPIRVDecompiler::ImageLoad,
&SPIRVDecompiler::ImageStore,
&SPIRVDecompiler::AtomicImageAdd,
- &SPIRVDecompiler::AtomicImageMin,
- &SPIRVDecompiler::AtomicImageMax,
&SPIRVDecompiler::AtomicImageAnd,
&SPIRVDecompiler::AtomicImageOr,
&SPIRVDecompiler::AtomicImageXor,
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
index d54fb88c9..95ec1cdd9 100644
--- a/src/video_core/shader/decode/image.cpp
+++ b/src/video_core/shader/decode/image.cpp
@@ -41,11 +41,46 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
const Instruction instr = {program_code[pc]};
const auto opcode = OpCode::Decode(instr);
+ const auto GetCoordinates = [this, instr](Tegra::Shader::ImageType image_type) {
+ std::vector<Node> coords;
+ const std::size_t num_coords{GetImageTypeNumCoordinates(image_type)};
+ coords.reserve(num_coords);
+ for (std::size_t i = 0; i < num_coords; ++i) {
+ coords.push_back(GetRegister(instr.gpr8.Value() + i));
+ }
+ return coords;
+ };
+
switch (opcode->get().GetId()) {
+ case OpCode::Id::SULD: {
+ UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P);
+ UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store !=
+ Tegra::Shader::OutOfBoundsStore::Ignore);
+
+ const auto type{instr.suldst.image_type};
+ auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type)
+ : GetBindlessImage(instr.gpr39, type)};
+ image.MarkRead();
+
+ u32 indexer = 0;
+ for (u32 element = 0; element < 4; ++element) {
+ if (!instr.suldst.IsComponentEnabled(element)) {
+ continue;
+ }
+ MetaImage meta{image, {}, element};
+ Node value = Operation(OperationCode::ImageLoad, meta, GetCoordinates(type));
+ SetTemporary(bb, indexer++, std::move(value));
+ }
+ for (u32 i = 0; i < indexer; ++i) {
+ SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
+ }
+ break;
+ }
case OpCode::Id::SUST: {
- UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P);
- UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore);
- UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store
+ UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P);
+ UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store !=
+ Tegra::Shader::OutOfBoundsStore::Ignore);
+ UNIMPLEMENTED_IF(instr.suldst.component_mask_selector != 0xf); // Ensure we have RGBA
std::vector<Node> values;
constexpr std::size_t hardcoded_size{4};
@@ -53,58 +88,51 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
values.push_back(GetRegister(instr.gpr0.Value() + i));
}
- std::vector<Node> coords;
- const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
- for (std::size_t i = 0; i < num_coords; ++i) {
- coords.push_back(GetRegister(instr.gpr8.Value() + i));
- }
-
- const auto type{instr.sust.image_type};
- auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
- : GetBindlessImage(instr.gpr39, type)};
+ const auto type{instr.suldst.image_type};
+ auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type)
+ : GetBindlessImage(instr.gpr39, type)};
image.MarkWrite();
- MetaImage meta{image, values};
- bb.push_back(Operation(OperationCode::ImageStore, meta, std::move(coords)));
+ MetaImage meta{image, std::move(values)};
+ bb.push_back(Operation(OperationCode::ImageStore, meta, GetCoordinates(type)));
break;
}
case OpCode::Id::SUATOM: {
UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0);
- Node value = GetRegister(instr.gpr0);
-
- std::vector<Node> coords;
- const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
- for (std::size_t i = 0; i < num_coords; ++i) {
- coords.push_back(GetRegister(instr.gpr8.Value() + i));
- }
-
const OperationCode operation_code = [instr] {
- switch (instr.suatom_d.operation) {
- case Tegra::Shader::ImageAtomicOperation::Add:
- return OperationCode::AtomicImageAdd;
- case Tegra::Shader::ImageAtomicOperation::Min:
- return OperationCode::AtomicImageMin;
- case Tegra::Shader::ImageAtomicOperation::Max:
- return OperationCode::AtomicImageMax;
- case Tegra::Shader::ImageAtomicOperation::And:
- return OperationCode::AtomicImageAnd;
- case Tegra::Shader::ImageAtomicOperation::Or:
- return OperationCode::AtomicImageOr;
- case Tegra::Shader::ImageAtomicOperation::Xor:
- return OperationCode::AtomicImageXor;
- case Tegra::Shader::ImageAtomicOperation::Exch:
- return OperationCode::AtomicImageExchange;
+ switch (instr.suatom_d.operation_type) {
+ case Tegra::Shader::ImageAtomicOperationType::S32:
+ case Tegra::Shader::ImageAtomicOperationType::U32:
+ switch (instr.suatom_d.operation) {
+ case Tegra::Shader::ImageAtomicOperation::Add:
+ return OperationCode::AtomicImageAdd;
+ case Tegra::Shader::ImageAtomicOperation::And:
+ return OperationCode::AtomicImageAnd;
+ case Tegra::Shader::ImageAtomicOperation::Or:
+ return OperationCode::AtomicImageOr;
+ case Tegra::Shader::ImageAtomicOperation::Xor:
+ return OperationCode::AtomicImageXor;
+ case Tegra::Shader::ImageAtomicOperation::Exch:
+ return OperationCode::AtomicImageExchange;
+ }
default:
- UNIMPLEMENTED_MSG("Unimplemented operation={}",
- static_cast<u32>(instr.suatom_d.operation.Value()));
- return OperationCode::AtomicImageAdd;
+ break;
}
+ UNIMPLEMENTED_MSG("Unimplemented operation={} type={}",
+ static_cast<u64>(instr.suatom_d.operation.Value()),
+ static_cast<u64>(instr.suatom_d.operation_type.Value()));
+ return OperationCode::AtomicImageAdd;
}();
- const auto& image{GetImage(instr.image, instr.suatom_d.image_type, instr.suatom_d.size)};
+ Node value = GetRegister(instr.gpr0);
+
+ const auto type = instr.suatom_d.image_type;
+ auto& image = GetImage(instr.image, type);
+ image.MarkAtomic();
+
MetaImage meta{image, {std::move(value)}};
- SetRegister(bb, instr.gpr0, Operation(operation_code, meta, std::move(coords)));
+ SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type)));
break;
}
default:
@@ -114,35 +142,32 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
return pc;
}
-Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size) {
+Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
const auto offset{static_cast<std::size_t>(image.index.Value())};
- if (const auto image = TryUseExistingImage(offset, type, size)) {
+ if (const auto image = TryUseExistingImage(offset, type)) {
return *image;
}
const std::size_t next_index{used_images.size()};
- return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second;
+ return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
}
-Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size) {
+Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
const Node image_register{GetRegister(reg)};
const auto [base_image, cbuf_index, cbuf_offset]{
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
- if (const auto image = TryUseExistingImage(cbuf_key, type, size)) {
+ if (const auto image = TryUseExistingImage(cbuf_key, type)) {
return *image;
}
const std::size_t next_index{used_images.size()};
- return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size})
+ return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
.first->second;
}
-Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size) {
+Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type) {
auto it = used_images.find(offset);
if (it == used_images.end()) {
return nullptr;
@@ -150,14 +175,6 @@ Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
auto& image = it->second;
ASSERT(image.GetType() == type);
- if (size) {
- // We know the size, if it's known it has to be the same as before, otherwise we can set it.
- if (image.IsSizeKnown()) {
- ASSERT(image.GetSize() == size);
- } else {
- image.SetSize(*size);
- }
- }
return &image;
}
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index abf2cb1ab..338bab17c 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -149,10 +149,10 @@ enum class OperationCode {
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
TexelFetch, /// (MetaTexture, int[N], int) -> float4
- ImageStore, /// (MetaImage, int[N] values) -> void
+ ImageLoad, /// (MetaImage, int[N] coords) -> void
+ ImageStore, /// (MetaImage, int[N] coords) -> void
+
AtomicImageAdd, /// (MetaImage, int[N] coords) -> void
- AtomicImageMin, /// (MetaImage, int[N] coords) -> void
- AtomicImageMax, /// (MetaImage, int[N] coords) -> void
AtomicImageAnd, /// (MetaImage, int[N] coords) -> void
AtomicImageOr, /// (MetaImage, int[N] coords) -> void
AtomicImageXor, /// (MetaImage, int[N] coords) -> void
@@ -294,21 +294,18 @@ private:
class Image final {
public:
- constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size)
- : offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {}
+ constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
+ : offset{offset}, index{index}, type{type}, is_bindless{false} {}
constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
- Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size)
+ Tegra::Shader::ImageType type)
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
- is_bindless{true}, size{size} {}
+ is_bindless{true} {}
constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
- bool is_bindless, bool is_written, bool is_read,
- std::optional<Tegra::Shader::ImageAtomicSize> size)
+ bool is_bindless, bool is_written, bool is_read, bool is_atomic)
: offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
- is_written{is_written}, is_read{is_read}, size{size} {}
+ is_written{is_written}, is_read{is_read}, is_atomic{is_atomic} {}
void MarkWrite() {
is_written = true;
@@ -318,8 +315,10 @@ public:
is_read = true;
}
- void SetSize(Tegra::Shader::ImageAtomicSize size_) {
- size = size_;
+ void MarkAtomic() {
+ MarkWrite();
+ MarkRead();
+ is_atomic = true;
}
constexpr std::size_t GetOffset() const {
@@ -346,21 +345,17 @@ public:
return is_read;
}
- constexpr std::pair<u32, u32> GetBindlessCBuf() const {
- return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
+ constexpr bool IsAtomic() const {
+ return is_atomic;
}
- constexpr bool IsSizeKnown() const {
- return size.has_value();
- }
-
- constexpr Tegra::Shader::ImageAtomicSize GetSize() const {
- return size.value();
+ constexpr std::pair<u32, u32> GetBindlessCBuf() const {
+ return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
}
constexpr bool operator<(const Image& rhs) const {
- return std::tie(offset, index, type, size, is_bindless) <
- std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless);
+ return std::tie(offset, index, type, is_bindless) <
+ std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
}
private:
@@ -370,7 +365,7 @@ private:
bool is_bindless{};
bool is_written{};
bool is_read{};
- std::optional<Tegra::Shader::ImageAtomicSize> size{};
+ bool is_atomic{};
};
struct GlobalMemoryBase {
@@ -402,6 +397,7 @@ struct MetaTexture {
struct MetaImage {
const Image& image;
std::vector<Node> values;
+ u32 element{};
};
/// Parameters that modify an operation but are not part of any particular operand
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index bbbab0bca..2c357f310 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -114,6 +114,18 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
break;
}
}
+ if (index == Attribute::Index::TessCoordInstanceIDVertexID) {
+ switch (element) {
+ case 2:
+ uses_instance_id = true;
+ break;
+ case 3:
+ uses_vertex_id = true;
+ break;
+ default:
+ break;
+ }
+ }
if (index == Attribute::Index::ClipDistances0123 ||
index == Attribute::Index::ClipDistances4567) {
const auto clip_index =
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 6aed9bb84..6f666ee30 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -124,6 +124,14 @@ public:
return uses_point_size;
}
+ bool UsesInstanceId() const {
+ return uses_instance_id;
+ }
+
+ bool UsesVertexId() const {
+ return uses_vertex_id;
+ }
+
bool HasPhysicalAttributes() const {
return uses_physical_attributes;
}
@@ -276,16 +284,13 @@ private:
bool is_shadow);
/// Accesses an image.
- Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size = {});
+ Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
/// Access a bindless image sampler.
- Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size = {});
+ Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
/// Tries to access an existing image, updating it's state as needed
- Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
- std::optional<Tegra::Shader::ImageAtomicSize> size);
+ Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type);
/// Extracts a sequence of bits from a node
Node BitfieldExtract(Node value, u32 offset, u32 bits);
@@ -373,6 +378,8 @@ private:
bool uses_viewport_index{};
bool uses_point_size{};
bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
+ bool uses_instance_id{};
+ bool uses_vertex_id{};
Tegra::Shader::Header header;
};
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 53d0142cb..250afc6d6 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -159,6 +159,8 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format)
return PixelFormat::R32UI;
case Tegra::RenderTargetFormat::RG32_UINT:
return PixelFormat::RG32UI;
+ case Tegra::RenderTargetFormat::RGBX16_FLOAT:
+ return PixelFormat::RGBX16F;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -415,6 +417,7 @@ ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
case Tegra::RenderTargetFormat::RG8_SNORM:
return ComponentType::SNorm;
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
+ case Tegra::RenderTargetFormat::RGBX16_FLOAT:
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
case Tegra::RenderTargetFormat::RG32_FLOAT:
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 19268b7cd..1e1c432a5 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -57,36 +57,37 @@ enum class PixelFormat {
RG8U = 39,
RG8S = 40,
RG32UI = 41,
- R32UI = 42,
- ASTC_2D_8X8 = 43,
- ASTC_2D_8X5 = 44,
- ASTC_2D_5X4 = 45,
- BGRA8_SRGB = 46,
- DXT1_SRGB = 47,
- DXT23_SRGB = 48,
- DXT45_SRGB = 49,
- BC7U_SRGB = 50,
- ASTC_2D_4X4_SRGB = 51,
- ASTC_2D_8X8_SRGB = 52,
- ASTC_2D_8X5_SRGB = 53,
- ASTC_2D_5X4_SRGB = 54,
- ASTC_2D_5X5 = 55,
- ASTC_2D_5X5_SRGB = 56,
- ASTC_2D_10X8 = 57,
- ASTC_2D_10X8_SRGB = 58,
+ RGBX16F = 42,
+ R32UI = 43,
+ ASTC_2D_8X8 = 44,
+ ASTC_2D_8X5 = 45,
+ ASTC_2D_5X4 = 46,
+ BGRA8_SRGB = 47,
+ DXT1_SRGB = 48,
+ DXT23_SRGB = 49,
+ DXT45_SRGB = 50,
+ BC7U_SRGB = 51,
+ ASTC_2D_4X4_SRGB = 52,
+ ASTC_2D_8X8_SRGB = 53,
+ ASTC_2D_8X5_SRGB = 54,
+ ASTC_2D_5X4_SRGB = 55,
+ ASTC_2D_5X5 = 56,
+ ASTC_2D_5X5_SRGB = 57,
+ ASTC_2D_10X8 = 58,
+ ASTC_2D_10X8_SRGB = 59,
MaxColorFormat,
// Depth formats
- Z32F = 59,
- Z16 = 60,
+ Z32F = 60,
+ Z16 = 61,
MaxDepthFormat,
// DepthStencil formats
- Z24S8 = 61,
- S8Z24 = 62,
- Z32FS8 = 63,
+ Z24S8 = 62,
+ S8Z24 = 63,
+ Z32FS8 = 64,
MaxDepthStencilFormat,
@@ -166,6 +167,7 @@ constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{
0, // RG8U
0, // RG8S
0, // RG32UI
+ 0, // RGBX16F
0, // R32UI
2, // ASTC_2D_8X8
2, // ASTC_2D_8X5
@@ -249,6 +251,7 @@ constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
1, // RG8U
1, // RG8S
1, // RG32UI
+ 1, // RGBX16F
1, // R32UI
8, // ASTC_2D_8X8
8, // ASTC_2D_8X5
@@ -324,6 +327,7 @@ constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
1, // RG8U
1, // RG8S
1, // RG32UI
+ 1, // RGBX16F
1, // R32UI
8, // ASTC_2D_8X8
5, // ASTC_2D_8X5
@@ -399,6 +403,7 @@ constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
16, // RG8U
16, // RG8S
64, // RG32UI
+ 64, // RGBX16F
32, // R32UI
128, // ASTC_2D_8X8
128, // ASTC_2D_8X5
@@ -489,6 +494,7 @@ constexpr std::array<SurfaceCompression, MaxPixelFormat> compression_type_table
SurfaceCompression::None, // RG8U
SurfaceCompression::None, // RG8S
SurfaceCompression::None, // RG32UI
+ SurfaceCompression::None, // RGBX16F
SurfaceCompression::None, // R32UI
SurfaceCompression::Converted, // ASTC_2D_8X8
SurfaceCompression::Converted, // ASTC_2D_8X5