summaryrefslogtreecommitdiffstats
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp24
-rw-r--r--src/video_core/engines/maxwell_dma.cpp4
-rw-r--r--src/video_core/macro/macro_hle.cpp7
-rw-r--r--src/video_core/query_cache.h39
-rw-r--r--src/video_core/rasterizer_interface.h8
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h5
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.cpp23
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp54
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h9
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h27
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp63
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp4
-rw-r--r--src/video_core/shader_environment.cpp35
-rw-r--r--src/video_core/shader_environment.h6
-rw-r--r--src/video_core/texture_cache/decode_bc.cpp50
-rw-r--r--src/video_core/texture_cache/decode_bc.h2
-rw-r--r--src/video_core/texture_cache/util.cpp16
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp21
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h4
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp6
27 files changed, 319 insertions, 135 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 592c28ba3..95ba4f76c 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -586,14 +586,22 @@ void Maxwell3D::ProcessQueryCondition() {
}
void Maxwell3D::ProcessCounterReset() {
- switch (regs.clear_report_value) {
- case Regs::ClearReport::ZPassPixelCount:
- rasterizer->ResetCounter(VideoCommon::QueryType::ZPassPixelCount64);
- break;
- default:
- LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}", regs.clear_report_value);
- break;
- }
+ const auto query_type = [clear_report = regs.clear_report_value]() {
+ switch (clear_report) {
+ case Tegra::Engines::Maxwell3D::Regs::ClearReport::ZPassPixelCount:
+ return VideoCommon::QueryType::ZPassPixelCount64;
+ case Tegra::Engines::Maxwell3D::Regs::ClearReport::StreamingPrimitivesSucceeded:
+ return VideoCommon::QueryType::StreamingPrimitivesSucceeded;
+ case Tegra::Engines::Maxwell3D::Regs::ClearReport::PrimitivesGenerated:
+ return VideoCommon::QueryType::PrimitivesGenerated;
+ case Tegra::Engines::Maxwell3D::Regs::ClearReport::VtgPrimitivesOut:
+ return VideoCommon::QueryType::VtgPrimitivesOut;
+ default:
+ LOG_DEBUG(HW_GPU, "Unimplemented counter reset={}", clear_report);
+ return VideoCommon::QueryType::Payload;
+ }
+ }();
+ rasterizer->ResetCounter(query_type);
}
void Maxwell3D::ProcessSyncPoint() {
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 422d4d859..56fbff306 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -228,7 +228,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
memory_manager, src_operand.address, src_size, &read_buffer);
- Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
+ Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadCachedWrite>
tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer);
UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth,
@@ -292,7 +292,7 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
GPUVAddr dst_addr = regs.offset_out;
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
memory_manager, src_addr, src_size, &read_buffer);
- Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
+ Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadCachedWrite>
tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer);
// If the input is linear and the output is tiled, swizzle the input and copy it over.
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 046c8085e..46e853e04 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -327,12 +327,13 @@ public:
explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
+ const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
+
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU);
- if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
+ if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) {
Fallback(parameters);
return;
}
-
auto& params = maxwell3d.draw_manager->GetIndirectParams();
params.is_byte_count = true;
params.is_indexed = false;
@@ -503,6 +504,8 @@ public:
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
regs.transform_feedback.controls[0].stride, true);
+
+ maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address());
}
};
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 9fcaeeac7..a64404ce4 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -28,8 +28,11 @@
namespace VideoCore {
enum class QueryType {
SamplesPassed,
+ PrimitivesGenerated,
+ TfbPrimitivesWritten,
+ Count,
};
-constexpr std::size_t NumQueryTypes = 1;
+constexpr std::size_t NumQueryTypes = static_cast<size_t>(QueryType::Count);
} // namespace VideoCore
namespace VideoCommon {
@@ -44,15 +47,6 @@ public:
explicit CounterStreamBase(QueryCache& cache_, VideoCore::QueryType type_)
: cache{cache_}, type{type_} {}
- /// Updates the state of the stream, enabling or disabling as needed.
- void Update(bool enabled) {
- if (enabled) {
- Enable();
- } else {
- Disable();
- }
- }
-
/// Resets the stream to zero. It doesn't disable the query after resetting.
void Reset() {
if (current) {
@@ -80,7 +74,6 @@ public:
return current != nullptr;
}
-private:
/// Enables the stream.
void Enable() {
if (current) {
@@ -97,6 +90,7 @@ private:
last = std::exchange(current, nullptr);
}
+private:
QueryCache& cache;
const VideoCore::QueryType type;
@@ -112,8 +106,14 @@ public:
: rasterizer{rasterizer_},
// Use reinterpret_cast instead of static_cast as workaround for
// UBSan bug (https://github.com/llvm/llvm-project/issues/59060)
- cpu_memory{cpu_memory_}, streams{{CounterStream{reinterpret_cast<QueryCache&>(*this),
- VideoCore::QueryType::SamplesPassed}}} {
+ cpu_memory{cpu_memory_}, streams{{
+ {CounterStream{reinterpret_cast<QueryCache&>(*this),
+ VideoCore::QueryType::SamplesPassed}},
+ {CounterStream{reinterpret_cast<QueryCache&>(*this),
+ VideoCore::QueryType::PrimitivesGenerated}},
+ {CounterStream{reinterpret_cast<QueryCache&>(*this),
+ VideoCore::QueryType::TfbPrimitivesWritten}},
+ }} {
(void)slot_async_jobs.insert(); // Null value
}
@@ -157,12 +157,11 @@ public:
AsyncFlushQuery(query, timestamp, lock);
}
- /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
- void UpdateCounters() {
+ /// Enables all available GPU counters
+ void EnableCounters() {
std::unique_lock lock{mutex};
- if (maxwell3d) {
- const auto& regs = maxwell3d->regs;
- Stream(VideoCore::QueryType::SamplesPassed).Update(regs.zpass_pixel_count_enable);
+ for (auto& stream : streams) {
+ stream.Enable();
}
}
@@ -176,7 +175,7 @@ public:
void DisableStreams() {
std::unique_lock lock{mutex};
for (auto& stream : streams) {
- stream.Update(false);
+ stream.Disable();
}
}
@@ -353,7 +352,7 @@ private:
std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{};
std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes;
-};
+}; // namespace VideoCommon
template <class QueryCache, class HostCounter>
class HostCounterBase {
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index af1469147..49224ca85 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -173,5 +173,13 @@ public:
virtual void BindChannel(Tegra::Control::ChannelState& channel) {}
virtual void ReleaseChannel(s32 channel_id) {}
+
+ /// Register the address as a Transform Feedback Object
+ virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {}
+
+ /// Returns true when the rasterizer has Draw Transform Feedback capabilities
+ virtual bool HasDrawTransformFeedback() {
+ return false;
+ }
};
} // namespace VideoCore
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index b787b6994..517ac14dd 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -376,4 +376,15 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P
*image_handles++ = buffer.View(offset, size, format);
}
+void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) {
+ OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr];
+ tfb_object.Create();
+ glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle);
+}
+
+GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) {
+ ASSERT(tfb_objects.contains(tfb_object_addr));
+ return tfb_objects[tfb_object_addr].handle;
+}
+
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 1e8708f59..2c18de166 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -5,6 +5,7 @@
#include <array>
#include <span>
+#include <unordered_map>
#include "common/common_types.h"
#include "video_core/buffer_cache/buffer_cache_base.h"
@@ -121,6 +122,9 @@ public:
void BindImageBuffer(Buffer& buffer, u32 offset, u32 size,
VideoCore::Surface::PixelFormat format);
+ void BindTransformFeedbackObject(GPUVAddr tfb_object_addr);
+ GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr);
+
u64 GetDeviceMemoryUsage() const;
void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) {
@@ -233,6 +237,7 @@ private:
u32 index_buffer_offset = 0;
u64 device_access_memory;
+ std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects;
};
struct BufferCacheParams {
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp
index ec142d48e..fef7360ed 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_query_cache.cpp
@@ -18,16 +18,27 @@ namespace OpenGL {
namespace {
-constexpr std::array<GLenum, VideoCore::NumQueryTypes> QueryTargets = {GL_SAMPLES_PASSED};
-
constexpr GLenum GetTarget(VideoCore::QueryType type) {
- return QueryTargets[static_cast<std::size_t>(type)];
+ switch (type) {
+ case VideoCore::QueryType::SamplesPassed:
+ return GL_SAMPLES_PASSED;
+ case VideoCore::QueryType::PrimitivesGenerated:
+ return GL_PRIMITIVES_GENERATED;
+ case VideoCore::QueryType::TfbPrimitivesWritten:
+ return GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN;
+ default:
+ break;
+ }
+ UNIMPLEMENTED_MSG("Query type {}", type);
+ return 0;
}
} // Anonymous namespace
QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_)
- : QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {}
+ : QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {
+ EnableCounters();
+}
QueryCache::~QueryCache() = default;
@@ -103,13 +114,13 @@ u64 CachedQuery::Flush([[maybe_unused]] bool async) {
auto& stream = cache->Stream(type);
const bool slice_counter = WaitPending() && stream.IsEnabled();
if (slice_counter) {
- stream.Update(false);
+ stream.Disable();
}
auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush();
if (slice_counter) {
- stream.Update(true);
+ stream.Enable();
}
return result;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4832c03c5..7a5fad735 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -51,6 +51,22 @@ constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
void oglEnable(GLenum cap, bool state) {
(state ? glEnable : glDisable)(cap);
}
+
+std::optional<VideoCore::QueryType> MaxwellToVideoCoreQuery(VideoCommon::QueryType type) {
+ switch (type) {
+ case VideoCommon::QueryType::PrimitivesGenerated:
+ case VideoCommon::QueryType::VtgPrimitivesOut:
+ return VideoCore::QueryType::PrimitivesGenerated;
+ case VideoCommon::QueryType::ZPassPixelCount64:
+ return VideoCore::QueryType::SamplesPassed;
+ case VideoCommon::QueryType::StreamingPrimitivesSucceeded:
+ // case VideoCommon::QueryType::StreamingByteCount:
+ // TODO: StreamingByteCount = StreamingPrimitivesSucceeded * num_verts * vert_stride
+ return VideoCore::QueryType::TfbPrimitivesWritten;
+ default:
+ return std::nullopt;
+ }
+}
} // Anonymous namespace
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -216,7 +232,6 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
SCOPE_EXIT({ gpu.TickWork(); });
gpu_memory->FlushCaching();
- query_cache.UpdateCounters();
GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
if (!pipeline) {
@@ -294,6 +309,13 @@ void RasterizerOpenGL::DrawIndirect() {
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
buffer_cache.SetDrawIndirect(&params);
PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) {
+ if (params.is_byte_count) {
+ const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
+ const GLuint tfb_object =
+ buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr);
+ glDrawTransformFeedback(primitive_mode, tfb_object);
+ return;
+ }
const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer();
const GLvoid* const gl_offset =
reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset));
@@ -334,7 +356,6 @@ void RasterizerOpenGL::DrawTexture() {
MICROPROFILE_SCOPE(OpenGL_Drawing);
SCOPE_EXIT({ gpu.TickWork(); });
- query_cache.UpdateCounters();
texture_cache.SynchronizeGraphicsDescriptors();
texture_cache.UpdateRenderTargets(false);
@@ -401,21 +422,28 @@ void RasterizerOpenGL::DispatchCompute() {
}
void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) {
- if (type == VideoCommon::QueryType::ZPassPixelCount64) {
- query_cache.ResetCounter(VideoCore::QueryType::SamplesPassed);
+ const auto query_cache_type = MaxwellToVideoCoreQuery(type);
+ if (!query_cache_type.has_value()) {
+ UNIMPLEMENTED_IF_MSG(type != VideoCommon::QueryType::Payload, "Reset query type: {}", type);
+ return;
}
+ query_cache.ResetCounter(*query_cache_type);
}
void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type,
VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport) {
- if (type == VideoCommon::QueryType::ZPassPixelCount64) {
- if (True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout)) {
- query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, {gpu.GetTicks()});
- } else {
- query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, std::nullopt);
- }
- return;
+ const auto query_cache_type = MaxwellToVideoCoreQuery(type);
+ if (!query_cache_type.has_value()) {
+ return QueryFallback(gpu_addr, type, flags, payload, subreport);
}
+ const bool has_timeout = True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout);
+ const auto timestamp = has_timeout ? std::optional<u64>{gpu.GetTicks()} : std::nullopt;
+ query_cache.Query(gpu_addr, *query_cache_type, timestamp);
+}
+
+void RasterizerOpenGL::QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type,
+ VideoCommon::QueryPropertiesFlags flags, u32 payload,
+ u32 subreport) {
if (type != VideoCommon::QueryType::Payload) {
payload = 1u;
}
@@ -1350,6 +1378,10 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) {
query_cache.EraseChannel(channel_id);
}
+void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) {
+ buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr);
+}
+
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_)
: buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ceffe1f1e..ce3460938 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -139,6 +139,12 @@ public:
void ReleaseChannel(s32 channel_id) override;
+ void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override;
+
+ bool HasDrawTransformFeedback() override {
+ return true;
+ }
+
private:
static constexpr size_t MAX_TEXTURES = 192;
static constexpr size_t MAX_IMAGES = 48;
@@ -225,6 +231,9 @@ private:
/// End a transform feedback
void EndTransformFeedback();
+ void QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type,
+ VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport);
+
Tegra::GPU& gpu;
const Device& device;
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index eae8fd110..1d2c9b70a 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -207,4 +207,21 @@ void OGLQuery::Release() {
handle = 0;
}
+void OGLTransformFeedback::Create() {
+ if (handle != 0)
+ return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
+ glCreateTransformFeedbacks(1, &handle);
+}
+
+void OGLTransformFeedback::Release() {
+ if (handle == 0)
+ return;
+
+ MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
+ glDeleteTransformFeedbacks(1, &handle);
+ handle = 0;
+}
+
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 77362acd2..6ca8227bd 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -323,4 +323,31 @@ public:
GLuint handle = 0;
};
+class OGLTransformFeedback final {
+public:
+ YUZU_NON_COPYABLE(OGLTransformFeedback);
+
+ OGLTransformFeedback() = default;
+
+ OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
+ ~OGLTransformFeedback() {
+ Release();
+ }
+
+ OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
+ return *this;
+ }
+
+ /// Creates a new internal OpenGL resource and stores the handle
+ void Create();
+
+ /// Deletes the internal OpenGL resource
+ void Release();
+
+ GLuint handle = 0;
+};
+
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 26f2d0ea7..30df41b7d 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -51,7 +51,7 @@ using VideoCommon::LoadPipelines;
using VideoCommon::SerializePipeline;
using Context = ShaderContext::Context;
-constexpr u32 CACHE_VERSION = 9;
+constexpr u32 CACHE_VERSION = 10;
template <typename Container>
auto MakeSpan(Container& container) {
@@ -233,6 +233,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
.ignore_nan_fp_comparisons = true,
.gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(),
.min_ssbo_alignment = device.GetShaderStorageBufferAlignment(),
+ .max_user_clip_distances = 8,
},
host_info{
.support_float64 = true,
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 5958f52f7..3c61799fa 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -78,8 +78,15 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
}
} // Anonymous namespace
-Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params)
- : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} {}
+Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params)
+ : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} {
+ if (runtime.device.HasNullDescriptor()) {
+ return;
+ }
+ device = &runtime.device;
+ buffer = runtime.CreateNullBuffer();
+ is_null = true;
+}
Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_,
VAddr cpu_addr_, u64 size_bytes_)
@@ -93,8 +100,12 @@ Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rast
VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format) {
if (!device) {
- // Null buffer, return a null descriptor
+ // Null buffer supported, return a null descriptor
return VK_NULL_HANDLE;
+ } else if (is_null) {
+ // Null buffer not supported, adjust offset and size
+ offset = 0;
+ size = 0;
}
const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) {
return offset == view.offset && size == view.size && format == view.format;
@@ -563,22 +574,27 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
}
buffer_handles.push_back(handle);
}
+ const u32 device_max = device.GetMaxVertexInputBindings();
+ const u32 min_binding = std::min(bindings.min_index, device_max);
+ const u32 max_binding = std::min(bindings.max_index, device_max);
+ const u32 binding_count = max_binding - min_binding;
+ if (binding_count == 0) {
+ return;
+ }
if (device.IsExtExtendedDynamicStateSupported()) {
- scheduler.Record([this, bindings_ = std::move(bindings),
- buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
- cmdbuf.BindVertexBuffers2EXT(bindings_.min_index,
- std::min(bindings_.max_index - bindings_.min_index,
- device.GetMaxVertexInputBindings()),
- buffer_handles_.data(), bindings_.offsets.data(),
- bindings_.sizes.data(), bindings_.strides.data());
+ scheduler.Record([bindings_ = std::move(bindings),
+ buffer_handles_ = std::move(buffer_handles),
+ binding_count](vk::CommandBuffer cmdbuf) {
+ cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(),
+ bindings_.offsets.data(), bindings_.sizes.data(),
+ bindings_.strides.data());
});
} else {
- scheduler.Record([this, bindings_ = std::move(bindings),
- buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
- cmdbuf.BindVertexBuffers(bindings_.min_index,
- std::min(bindings_.max_index - bindings_.min_index,
- device.GetMaxVertexInputBindings()),
- buffer_handles_.data(), bindings_.offsets.data());
+ scheduler.Record([bindings_ = std::move(bindings),
+ buffer_handles_ = std::move(buffer_handles),
+ binding_count](vk::CommandBuffer cmdbuf) {
+ cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(),
+ bindings_.offsets.data());
});
}
}
@@ -622,9 +638,12 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
}
void BufferCacheRuntime::ReserveNullBuffer() {
- if (null_buffer) {
- return;
+ if (!null_buffer) {
+ null_buffer = CreateNullBuffer();
}
+}
+
+vk::Buffer BufferCacheRuntime::CreateNullBuffer() {
VkBufferCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -639,15 +658,17 @@ void BufferCacheRuntime::ReserveNullBuffer() {
if (device.IsExtTransformFeedbackSupported()) {
create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
- null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
+ vk::Buffer ret = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
if (device.HasDebuggingToolAttached()) {
- null_buffer.SetObjectNameEXT("Null buffer");
+ ret.SetObjectNameEXT("Null buffer");
}
scheduler.RequestOutsideRenderPassOperationContext();
- scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) {
+ scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) {
cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0);
});
+
+ return ret;
}
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 0b3fbd6d0..dc300d7cb 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -63,6 +63,7 @@ private:
vk::Buffer buffer;
std::vector<BufferView> views;
VideoCommon::UsageTracker tracker;
+ bool is_null{};
};
class QuadArrayIndexBuffer;
@@ -151,6 +152,7 @@ private:
}
void ReserveNullBuffer();
+ vk::Buffer CreateNullBuffer();
const Device& device;
MemoryAllocator& memory_allocator;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 2a13b2a72..d1841198d 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment;
using VideoCommon::GenericEnvironment;
using VideoCommon::GraphicsEnvironment;
-constexpr u32 CACHE_VERSION = 10;
+constexpr u32 CACHE_VERSION = 11;
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
template <typename Container>
@@ -374,6 +374,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.has_broken_robust =
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
.min_ssbo_alignment = device.GetStorageBufferAlignment(),
+ .max_user_clip_distances = device.GetMaxUserClipDistances(),
};
host_info = Shader::HostTranslateInfo{
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index 5e7518d96..792ed9615 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -329,7 +329,7 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) {
// to account for that.
const bool is_suboptimal = swapchain.NeedsRecreation();
const bool size_changed =
- swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
+ swapchain.GetWidth() < frame->width || swapchain.GetHeight() < frame->height;
if (is_suboptimal || size_changed) {
RecreateSwapchain(frame);
}
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 078777cdd..95954ade7 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -289,12 +289,15 @@ public:
}
if (has_multi_queries) {
- size_t intermediary_buffer_index = ObtainBuffer<false>(num_slots_used);
+ const size_t min_accumulation_limit =
+ std::min(first_accumulation_checkpoint, num_slots_used);
+ const size_t max_accumulation_limit =
+ std::max(last_accumulation_checkpoint, num_slots_used);
+ const size_t intermediary_buffer_index = ObtainBuffer<false>(num_slots_used);
resolve_buffers.push_back(intermediary_buffer_index);
queries_prefix_scan_pass->Run(*accumulation_buffer, *buffers[intermediary_buffer_index],
*buffers[resolve_buffer_index], num_slots_used,
- std::min(first_accumulation_checkpoint, num_slots_used),
- last_accumulation_checkpoint);
+ min_accumulation_limit, max_accumulation_limit);
} else {
scheduler.RequestOutsideRenderPassOperationContext();
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 59829c88b..241fc34be 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -485,6 +485,10 @@ void RasterizerVulkan::DispatchCompute() {
}
void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) {
+ if (type != VideoCommon::QueryType::ZPassPixelCount64) {
+ LOG_DEBUG(Render_Vulkan, "Unimplemented counter reset={}", type);
+ return;
+ }
query_cache.CounterReset(type);
}
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 4edbe5700..492440ac4 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -62,23 +62,9 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en
}
static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) {
- switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type,
- entry.a_type, entry.srgb_conversion)) {
- case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM:
- return Shader::TexturePixelFormat::A8B8G8R8_SNORM;
- case VideoCore::Surface::PixelFormat::R8_SNORM:
- return Shader::TexturePixelFormat::R8_SNORM;
- case VideoCore::Surface::PixelFormat::R8G8_SNORM:
- return Shader::TexturePixelFormat::R8G8_SNORM;
- case VideoCore::Surface::PixelFormat::R16G16B16A16_SNORM:
- return Shader::TexturePixelFormat::R16G16B16A16_SNORM;
- case VideoCore::Surface::PixelFormat::R16G16_SNORM:
- return Shader::TexturePixelFormat::R16G16_SNORM;
- case VideoCore::Surface::PixelFormat::R16_SNORM:
- return Shader::TexturePixelFormat::R16_SNORM;
- default:
- return Shader::TexturePixelFormat::OTHER;
- }
+ return static_cast<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) {
@@ -398,6 +384,11 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl
return result;
}
+bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) {
+ return VideoCore::Surface::IsPixelFormatInteger(
+ static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
+}
+
u32 GraphicsEnvironment::ReadViewportTransformState() {
const auto& regs{maxwell3d->regs};
viewport_transform_state = regs.viewport_scale_offset_enabled;
@@ -448,6 +439,11 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle
return result;
}
+bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) {
+ return VideoCore::Surface::IsPixelFormatInteger(
+ static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
+}
+
u32 ComputeEnvironment::ReadViewportTransformState() {
return viewport_transform_state;
}
@@ -551,6 +547,11 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) {
return it->second;
}
+bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) {
+ return VideoCore::Surface::IsPixelFormatInteger(
+ static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
+}
+
u32 FileEnvironment::ReadViewportTransformState() {
return viewport_transform_state;
}
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h
index b90f3d44e..6b372e336 100644
--- a/src/video_core/shader_environment.h
+++ b/src/video_core/shader_environment.h
@@ -115,6 +115,8 @@ public:
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
+ bool IsTexturePixelFormatInteger(u32 handle) override;
+
u32 ReadViewportTransformState() override;
std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override;
@@ -139,6 +141,8 @@ public:
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
+ bool IsTexturePixelFormatInteger(u32 handle) override;
+
u32 ReadViewportTransformState() override;
std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(
@@ -171,6 +175,8 @@ public:
[[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
+ [[nodiscard]] bool IsTexturePixelFormatInteger(u32 handle) override;
+
[[nodiscard]] u32 ReadViewportTransformState() override;
[[nodiscard]] u32 LocalMemorySize() const override;
diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp
index 3e26474a3..a018c6df4 100644
--- a/src/video_core/texture_cache/decode_bc.cpp
+++ b/src/video_core/texture_cache/decode_bc.cpp
@@ -60,66 +60,72 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
}
template <auto decompress, PixelFormat pixel_format>
-void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
+void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
bool is_signed = false) {
const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
- const u32 block_width = std::min(extent.width, BLOCK_SIZE);
- const u32 block_height = std::min(extent.height, BLOCK_SIZE);
- const u32 pitch = extent.width * out_bpp;
+ const u32 block_size = BlockSize(pixel_format);
+ const u32 width = copy.image_extent.width;
+ const u32 height = copy.image_extent.height * copy.image_subresource.num_layers;
+ const u32 depth = copy.image_extent.depth;
+ const u32 block_width = std::min(width, BLOCK_SIZE);
+ const u32 block_height = std::min(height, BLOCK_SIZE);
+ const u32 pitch = width * out_bpp;
size_t input_offset = 0;
size_t output_offset = 0;
- for (u32 slice = 0; slice < extent.depth; ++slice) {
- for (u32 y = 0; y < extent.height; y += block_height) {
- size_t row_offset = 0;
- for (u32 x = 0; x < extent.width;
- x += block_width, row_offset += block_width * out_bpp) {
- const u8* src = input.data() + input_offset;
- u8* const dst = output.data() + output_offset + row_offset;
+ for (u32 slice = 0; slice < depth; ++slice) {
+ for (u32 y = 0; y < height; y += block_height) {
+ size_t src_offset = input_offset;
+ size_t dst_offset = output_offset;
+ for (u32 x = 0; x < width; x += block_width) {
+ const u8* src = input.data() + src_offset;
+ u8* const dst = output.data() + dst_offset;
if constexpr (IsSigned(pixel_format)) {
- decompress(src, dst, x, y, extent.width, extent.height, is_signed);
+ decompress(src, dst, x, y, width, height, is_signed);
} else {
- decompress(src, dst, x, y, extent.width, extent.height);
+ decompress(src, dst, x, y, width, height);
}
- input_offset += BlockSize(pixel_format);
+ src_offset += block_size;
+ dst_offset += block_width * out_bpp;
}
+ input_offset += copy.buffer_row_length * block_size / block_width;
output_offset += block_height * pitch;
}
}
}
-void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
+void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC1_RGBA_SRGB:
- DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
+ DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy);
break;
case PixelFormat::BC2_UNORM:
case PixelFormat::BC2_SRGB:
- DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
+ DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy);
break;
case PixelFormat::BC3_UNORM:
case PixelFormat::BC3_SRGB:
- DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
+ DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy);
break;
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
- input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
+ input, output, copy, pixel_format == PixelFormat::BC4_SNORM);
break;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
- input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
+ input, output, copy, pixel_format == PixelFormat::BC5_SNORM);
break;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
- input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
+ input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT);
break;
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM:
- DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
+ DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy);
break;
default:
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
diff --git a/src/video_core/texture_cache/decode_bc.h b/src/video_core/texture_cache/decode_bc.h
index 41d1ec0a3..4e3b9b8ac 100644
--- a/src/video_core/texture_cache/decode_bc.h
+++ b/src/video_core/texture_cache/decode_bc.h
@@ -13,7 +13,7 @@ namespace VideoCommon {
[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
-void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
+void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
VideoCore::Surface::PixelFormat pixel_format);
} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 15596c925..fcf70068e 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -837,6 +837,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
std::span<u8> output) {
const size_t guest_size_bytes = input.size_bytes();
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
+ const Extent2D tile_size = DefaultBlockSize(info.format);
const Extent3D size = info.size;
if (info.type == ImageType::Linear) {
@@ -847,7 +848,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
return {{
.buffer_offset = 0,
.buffer_size = guest_size_bytes,
- .buffer_row_length = info.pitch >> bpp_log2,
+ .buffer_row_length = info.pitch * tile_size.width >> bpp_log2,
.buffer_image_height = size.height,
.image_subresource =
{
@@ -862,7 +863,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
const LevelInfo level_info = MakeLevelInfo(info);
const s32 num_layers = info.resources.layers;
const s32 num_levels = info.resources.levels;
- const Extent2D tile_size = DefaultBlockSize(info.format);
const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels);
@@ -926,8 +926,6 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
const auto input_offset = input.subspan(copy.buffer_offset);
copy.buffer_offset = output_offset;
- copy.buffer_row_length = mip_size.width;
- copy.buffer_image_height = mip_size.height;
const auto recompression_setting = Settings::values.astc_recompression.GetValue();
const bool astc = IsPixelFormatASTC(info.format);
@@ -972,16 +970,14 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
bpp_div;
output_offset += static_cast<u32>(copy.buffer_size);
} else {
- const Extent3D image_extent{
- .width = copy.image_extent.width,
- .height = copy.image_extent.height * copy.image_subresource.num_layers,
- .depth = copy.image_extent.depth,
- };
- DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
+ DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_subresource.num_layers *
ConvertedBytesPerBlock(info.format);
}
+
+ copy.buffer_row_length = mip_size.width;
+ copy.buffer_image_height = mip_size.height;
}
}
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 1fda0042d..727bbd98d 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -695,6 +695,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
std::min(properties.properties.limits.maxVertexInputBindings, 16U);
}
+ if (is_turnip) {
+ LOG_WARNING(Render_Vulkan, "Turnip requires higher-than-reported binding limits");
+ properties.properties.limits.maxVertexInputBindings = 32;
+ }
+
if (!extensions.extended_dynamic_state && extensions.extended_dynamic_state2) {
LOG_INFO(Render_Vulkan,
"Removing extendedDynamicState2 due to missing extendedDynamicState");
@@ -750,10 +755,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
// The wanted format is not supported by hardware, search for alternatives
const VkFormat* alternatives = GetFormatAlternatives(wanted_format);
if (alternatives == nullptr) {
- ASSERT_MSG(false,
- "Format={} with usage={} and type={} has no defined alternatives and host "
- "hardware does not support it",
- wanted_format, wanted_usage, format_type);
+ LOG_ERROR(Render_Vulkan,
+ "Format={} with usage={} and type={} has no defined alternatives and host "
+ "hardware does not support it",
+ wanted_format, wanted_usage, format_type);
return wanted_format;
}
@@ -769,10 +774,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
}
// No alternatives found, panic
- ASSERT_MSG(false,
- "Format={} with usage={} and type={} is not supported by the host hardware and "
- "doesn't support any of the alternatives",
- wanted_format, wanted_usage, format_type);
+ LOG_ERROR(Render_Vulkan,
+ "Format={} with usage={} and type={} is not supported by the host hardware and "
+ "doesn't support any of the alternatives",
+ wanted_format, wanted_usage, format_type);
return wanted_format;
}
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 4f3846345..701817086 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -665,6 +665,10 @@ public:
return properties.properties.limits.maxViewports;
}
+ u32 GetMaxUserClipDistances() const {
+ return properties.properties.limits.maxClipDistances;
+ }
+
bool SupportsConditionalBarriers() const {
return supports_conditional_barriers;
}
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 70cf14afa..074aed964 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -246,7 +246,9 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec
.objectHandle = reinterpret_cast<u64>(handle),
.pObjectName = name,
};
- Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
+ if (dld->vkSetDebugUtilsObjectNameEXT) {
+ Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
+ }
}
} // Anonymous namespace
@@ -377,6 +379,8 @@ const char* ToString(VkResult result) noexcept {
return "VK_OPERATION_DEFERRED_KHR";
case VkResult::VK_OPERATION_NOT_DEFERRED_KHR:
return "VK_OPERATION_NOT_DEFERRED_KHR";
+ case VkResult::VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR:
+ return "VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR";
case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT:
return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
case VkResult::VK_RESULT_MAX_ENUM: