mirror of
https://git.suyu.dev/suyu/suyu
synced 2024-12-25 10:52:48 -06:00
rework the binding system
This commit is contained in:
parent
49f60adeb2
commit
3a51a8de2e
7 changed files with 320 additions and 184 deletions
|
@ -22,15 +22,6 @@ MTL::Buffer* CreatePrivateBuffer(const Device& device, size_t size) {
|
|||
|
||||
} // Anonymous namespace
|
||||
|
||||
BoundBuffer::BoundBuffer(MTL::Buffer* buffer_, size_t offset_, size_t size_)
|
||||
: buffer{buffer_->retain()}, offset{offset_}, size{size_} {}
|
||||
|
||||
BoundBuffer::~BoundBuffer() {
|
||||
if (buffer) {
|
||||
buffer->release();
|
||||
}
|
||||
}
|
||||
|
||||
BufferView::BufferView(MTL::Buffer* buffer_, size_t offset_, size_t size_,
|
||||
VideoCore::Surface::PixelFormat format_)
|
||||
: buffer{buffer_->retain()}, offset{offset_}, size{size_}, format{format_} {}
|
||||
|
@ -94,24 +85,29 @@ void BufferCacheRuntime::ClearBuffer(MTL::Buffer* dest_buffer, u32 offset, size_
|
|||
void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat index_format,
|
||||
u32 base_vertex, u32 num_indices, MTL::Buffer* buffer,
|
||||
u32 offset, [[maybe_unused]] u32 size) {
|
||||
// TODO: convert parameters to Metal enums
|
||||
bound_index_buffer = {BoundBuffer(buffer, offset, size)};
|
||||
command_recorder.SetIndexBuffer(buffer, offset, index_format, topology, num_indices,
|
||||
base_vertex);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count) {
|
||||
// TODO: bind quad index buffer
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffer(u32 index, MTL::Buffer* buffer, u32 offset, u32 size,
|
||||
u32 stride) {
|
||||
void BufferCacheRuntime::BindVertexBuffer(size_t stage, u32 index, MTL::Buffer* buffer, u32 offset,
|
||||
u32 size, u32 stride) {
|
||||
// TODO: use stride
|
||||
bound_vertex_buffers[MAX_METAL_BUFFERS - index - 1] = {BoundBuffer(buffer, offset, size)};
|
||||
BindBuffer(stage, MAX_METAL_BUFFERS - index - 1, buffer, offset, size);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindBuffer(size_t stage, u32 binding_index, MTL::Buffer* buffer,
|
||||
u32 offset, u32 size) {
|
||||
command_recorder.SetBuffer(stage, buffer, binding_index, offset);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::ReserveNullBuffer() {
|
||||
if (!null_buffer) {
|
||||
null_buffer = CreateNullBuffer();
|
||||
|
|
|
@ -17,17 +17,6 @@ class CommandRecorder;
|
|||
|
||||
class BufferCacheRuntime;
|
||||
|
||||
struct BoundBuffer {
|
||||
BoundBuffer() = default;
|
||||
BoundBuffer(MTL::Buffer* buffer_, size_t offset_, size_t size_);
|
||||
|
||||
~BoundBuffer();
|
||||
|
||||
MTL::Buffer* buffer = nil;
|
||||
size_t offset{};
|
||||
size_t size{};
|
||||
};
|
||||
|
||||
struct BufferView {
|
||||
BufferView(MTL::Buffer* buffer_, size_t offset_, size_t size_,
|
||||
VideoCore::Surface::PixelFormat format_ = VideoCore::Surface::PixelFormat::Invalid);
|
||||
|
@ -121,7 +110,8 @@ public:
|
|||
|
||||
void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count);
|
||||
|
||||
void BindVertexBuffer(u32 index, MTL::Buffer* buffer, u32 offset, u32 size, u32 stride);
|
||||
void BindVertexBuffer(size_t stage, u32 index, MTL::Buffer* buffer, u32 offset, u32 size,
|
||||
u32 stride);
|
||||
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||
|
||||
|
@ -131,31 +121,35 @@ public:
|
|||
// TODO: implement
|
||||
void BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings) {}
|
||||
|
||||
std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage,
|
||||
[[maybe_unused]] u32 binding_index, u32 size) {
|
||||
std::span<u8> BindMappedUniformBuffer(size_t stage, u32 binding_index, u32 size) {
|
||||
const StagingBufferRef ref = staging_pool.Request(size, MemoryUsage::Upload);
|
||||
BindBuffer(ref.buffer, static_cast<u32>(ref.offset), size);
|
||||
BindBuffer(stage, binding_index, ref.buffer, static_cast<u32>(ref.offset), size);
|
||||
return ref.mapped_span;
|
||||
}
|
||||
|
||||
void BindUniformBuffer(MTL::Buffer* buffer, u32 offset, u32 size) {
|
||||
BindBuffer(buffer, offset, size);
|
||||
void BindUniformBuffer(size_t stage, u32 binding_index, MTL::Buffer* buffer, u32 offset,
|
||||
u32 size) {
|
||||
BindBuffer(stage, binding_index, buffer, offset, size);
|
||||
}
|
||||
|
||||
void BindStorageBuffer(MTL::Buffer* buffer, u32 offset, u32 size,
|
||||
[[maybe_unused]] bool is_written) {
|
||||
BindBuffer(buffer, offset, size);
|
||||
// TODO: implement
|
||||
void BindComputeUniformBuffer(u32 binding_index, MTL::Buffer* buffer, u32 offset, u32 size) {}
|
||||
|
||||
void BindStorageBuffer(size_t stage, u32 binding_index, MTL::Buffer* buffer, u32 offset,
|
||||
u32 size, [[maybe_unused]] bool is_written) {
|
||||
BindBuffer(stage, binding_index, buffer, offset, size);
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
void BindComputeStorageBuffer(u32 binding_index, Buffer& buffer, u32 offset, u32 size,
|
||||
bool is_written) {}
|
||||
|
||||
// TODO: implement
|
||||
void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size,
|
||||
VideoCore::Surface::PixelFormat format) {}
|
||||
|
||||
private:
|
||||
void BindBuffer(MTL::Buffer* buffer, u32 offset, u32 size) {
|
||||
// FIXME: what should be the index?
|
||||
bound_buffers[0] = BoundBuffer(buffer, offset, size);
|
||||
}
|
||||
void BindBuffer(size_t stage, u32 binding_index, MTL::Buffer* buffer, u32 offset, u32 size);
|
||||
|
||||
void ReserveNullBuffer();
|
||||
MTL::Buffer* CreateNullBuffer();
|
||||
|
@ -167,17 +161,6 @@ private:
|
|||
// Common buffers
|
||||
MTL::Buffer* null_buffer = nil;
|
||||
MTL::Buffer* quad_index_buffer = nil;
|
||||
|
||||
// TODO: probably move this into a separate class
|
||||
// Bound state
|
||||
// Vertex buffers are bound to MAX_METAL_BUFFERS - index - 1, while regular buffers are bound to
|
||||
// index
|
||||
BoundBuffer bound_vertex_buffers[MAX_METAL_BUFFERS] = {{}};
|
||||
struct {
|
||||
BoundBuffer buffer;
|
||||
// TODO: include index type and primitive topology
|
||||
} bound_index_buffer = {};
|
||||
BoundBuffer bound_buffers[MAX_METAL_BUFFERS] = {{}};
|
||||
};
|
||||
|
||||
struct BufferCacheParams {
|
||||
|
@ -189,8 +172,8 @@ struct BufferCacheParams {
|
|||
static constexpr bool IS_OPENGL = false;
|
||||
static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = false;
|
||||
static constexpr bool HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT = false;
|
||||
static constexpr bool NEEDS_BIND_UNIFORM_INDEX = false;
|
||||
static constexpr bool NEEDS_BIND_STORAGE_INDEX = false;
|
||||
static constexpr bool NEEDS_BIND_UNIFORM_INDEX = true;
|
||||
static constexpr bool NEEDS_BIND_STORAGE_INDEX = true;
|
||||
static constexpr bool USE_MEMORY_MAPS = true;
|
||||
static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = false;
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = true;
|
||||
|
|
|
@ -11,12 +11,86 @@ CommandRecorder::CommandRecorder(const Device& device_) : device(device_) {}
|
|||
CommandRecorder::~CommandRecorder() = default;
|
||||
|
||||
void CommandRecorder::BeginOrContinueRenderPass(MTL::RenderPassDescriptor* render_pass) {
|
||||
bool should_reset_bound_resources = false;
|
||||
if (render_pass != render_state.render_pass) {
|
||||
RequireCommandBuffer();
|
||||
EndEncoding();
|
||||
RequireCommandBuffer();
|
||||
encoder = command_buffer->renderCommandEncoder(render_pass);
|
||||
encoder_type = EncoderType::Render;
|
||||
render_state.render_pass = render_pass;
|
||||
should_reset_bound_resources = true;
|
||||
}
|
||||
const auto bind_resources{[&](size_t stage) {
|
||||
// Buffers
|
||||
for (u8 i = 0; i < MAX_BUFFERS; i++) {
|
||||
auto& bound_buffer = render_state.buffers[stage][i];
|
||||
if (bound_buffer.buffer &&
|
||||
(bound_buffer.needs_update || should_reset_bound_resources)) {
|
||||
switch (stage) {
|
||||
case 0:
|
||||
GetRenderCommandEncoderUnchecked()->setVertexBuffer(bound_buffer.buffer, i,
|
||||
bound_buffer.offset);
|
||||
break;
|
||||
case 4:
|
||||
GetRenderCommandEncoderUnchecked()->setFragmentBuffer(bound_buffer.buffer, i,
|
||||
bound_buffer.offset);
|
||||
break;
|
||||
}
|
||||
bound_buffer.needs_update = false;
|
||||
}
|
||||
}
|
||||
// Textures
|
||||
for (u8 i = 0; i < MAX_TEXTURES; i++) {
|
||||
auto& bound_texture = render_state.textures[stage][i];
|
||||
if (bound_texture.texture &&
|
||||
(bound_texture.needs_update || should_reset_bound_resources)) {
|
||||
switch (stage) {
|
||||
case 0:
|
||||
GetRenderCommandEncoderUnchecked()->setVertexTexture(bound_texture.texture, i);
|
||||
break;
|
||||
case 4:
|
||||
GetRenderCommandEncoderUnchecked()->setFragmentTexture(bound_texture.texture,
|
||||
i);
|
||||
break;
|
||||
}
|
||||
bound_texture.needs_update = false;
|
||||
}
|
||||
}
|
||||
// Sampler states
|
||||
for (u8 i = 0; i < MAX_SAMPLERS; i++) {
|
||||
auto& bound_sampler_state = render_state.sampler_states[stage][i];
|
||||
if (bound_sampler_state.sampler_state &&
|
||||
(bound_sampler_state.needs_update || should_reset_bound_resources)) {
|
||||
switch (stage) {
|
||||
case 0:
|
||||
GetRenderCommandEncoderUnchecked()->setVertexSamplerState(
|
||||
bound_sampler_state.sampler_state, i);
|
||||
break;
|
||||
case 4:
|
||||
GetRenderCommandEncoderUnchecked()->setFragmentSamplerState(
|
||||
bound_sampler_state.sampler_state, i);
|
||||
break;
|
||||
}
|
||||
bound_sampler_state.needs_update = false;
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
bind_resources(0);
|
||||
bind_resources(4);
|
||||
|
||||
if (should_reset_bound_resources) {
|
||||
for (size_t stage = 0; stage < 5; stage++) {
|
||||
for (u8 i = 0; i < MAX_BUFFERS; i++) {
|
||||
render_state.buffers[stage][i].buffer = nullptr;
|
||||
}
|
||||
for (u8 i = 0; i < MAX_TEXTURES; i++) {
|
||||
render_state.textures[stage][i].texture = nullptr;
|
||||
}
|
||||
for (u8 i = 0; i < MAX_SAMPLERS; i++) {
|
||||
render_state.sampler_states[stage][i].sampler_state = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +118,8 @@ void CommandRecorder::EndEncoding() {
|
|||
//[encoder release];
|
||||
encoder = nullptr;
|
||||
if (encoder_type == EncoderType::Render) {
|
||||
render_state = {};
|
||||
render_state.render_pass = nullptr;
|
||||
render_state.pipeline_state = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
||||
namespace Metal {
|
||||
|
||||
class Device;
|
||||
|
@ -16,27 +18,48 @@ constexpr size_t MAX_BUFFERS = 31;
|
|||
constexpr size_t MAX_TEXTURES = 31;
|
||||
constexpr size_t MAX_SAMPLERS = 31;
|
||||
|
||||
struct BoundBuffer {
|
||||
bool needs_update{true};
|
||||
MTL::Buffer* buffer{nullptr};
|
||||
size_t offset{0};
|
||||
};
|
||||
|
||||
struct BoundTexture {
|
||||
bool needs_update{true};
|
||||
MTL::Texture* texture{nullptr};
|
||||
};
|
||||
|
||||
struct BoundSamplerState {
|
||||
bool needs_update{true};
|
||||
MTL::SamplerState* sampler_state{nullptr};
|
||||
};
|
||||
|
||||
struct BoundIndexBuffer {
|
||||
MTL::Buffer* buffer{nullptr};
|
||||
size_t offset{0};
|
||||
MTL::IndexType index_format;
|
||||
MTL::PrimitiveType primitive_topology;
|
||||
u32 num_indices;
|
||||
u32 base_vertex;
|
||||
};
|
||||
|
||||
struct RenderState {
|
||||
MTL::RenderPassDescriptor* render_pass{nullptr};
|
||||
MTL::RenderPipelineState* pipeline_state{nullptr};
|
||||
|
||||
MTL::Buffer* vertex_buffers[MAX_BUFFERS] = {nullptr};
|
||||
MTL::Buffer* fragment_buffers[MAX_BUFFERS] = {nullptr};
|
||||
MTL::Buffer* compute_buffers[MAX_BUFFERS] = {nullptr};
|
||||
|
||||
MTL::Texture* vertex_textures[MAX_TEXTURES] = {nullptr};
|
||||
MTL::Texture* fragment_textures[MAX_TEXTURES] = {nullptr};
|
||||
MTL::Texture* compute_textures[MAX_TEXTURES] = {nullptr};
|
||||
|
||||
MTL::SamplerState* vertex_sampler_states[MAX_SAMPLERS] = {nullptr};
|
||||
MTL::SamplerState* fragment_sampler_states[MAX_SAMPLERS] = {nullptr};
|
||||
MTL::SamplerState* compute_sampler_states[MAX_SAMPLERS] = {nullptr};
|
||||
BoundBuffer buffers[5][MAX_BUFFERS] = {{}};
|
||||
BoundTexture textures[5][MAX_TEXTURES] = {{}};
|
||||
BoundSamplerState sampler_states[5][MAX_SAMPLERS] = {{}};
|
||||
BoundIndexBuffer bound_index_buffer;
|
||||
};
|
||||
|
||||
// TODO: whenever a render pass gets interrupted by either a compute or blit command and application
|
||||
// then tries to perform a render command, begin the same render pass, but with all load actions set
|
||||
// to "load"
|
||||
class CommandRecorder {
|
||||
using PrimitiveTopology = Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology;
|
||||
using IndexFormat = Tegra::Engines::Maxwell3D::Regs::IndexFormat;
|
||||
|
||||
public:
|
||||
CommandRecorder(const Device& device_);
|
||||
~CommandRecorder();
|
||||
|
@ -64,10 +87,14 @@ public:
|
|||
return command_buffer;
|
||||
}
|
||||
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoderUnchecked() {
|
||||
return static_cast<MTL::RenderCommandEncoder*>(encoder);
|
||||
}
|
||||
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder() {
|
||||
CheckIfRenderPassIsActive();
|
||||
|
||||
return static_cast<MTL::RenderCommandEncoder*>(encoder);
|
||||
return GetRenderCommandEncoderUnchecked();
|
||||
}
|
||||
|
||||
MTL::ComputeCommandEncoder* GetComputeCommandEncoder() {
|
||||
|
@ -90,67 +117,34 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
inline void SetVertexBuffer(MTL::Buffer* buffer, size_t index) {
|
||||
if (buffer != render_state.vertex_buffers[index]) {
|
||||
GetRenderCommandEncoder()->setVertexBuffer(buffer, index, 0);
|
||||
render_state.vertex_buffers[index] = buffer;
|
||||
inline void SetBuffer(size_t stage, MTL::Buffer* buffer, size_t index, size_t offset) {
|
||||
auto& bound_buffer = render_state.buffers[stage][index];
|
||||
if (buffer != bound_buffer.buffer) {
|
||||
bound_buffer = {true, buffer, offset};
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetFragmentBuffer(MTL::Buffer* buffer, size_t index) {
|
||||
if (buffer != render_state.fragment_buffers[index]) {
|
||||
GetRenderCommandEncoder()->setFragmentBuffer(buffer, index, 0);
|
||||
render_state.fragment_buffers[index] = buffer;
|
||||
inline void SetTexture(size_t stage, MTL::Texture* texture, size_t index) {
|
||||
auto& bound_texture = render_state.textures[stage][index];
|
||||
if (texture != bound_texture.texture) {
|
||||
bound_texture = {true, texture};
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetComputeBuffer(MTL::Buffer* buffer, size_t index) {
|
||||
if (buffer != render_state.compute_buffers[index]) {
|
||||
GetComputeCommandEncoder()->setBuffer(buffer, index, 0);
|
||||
render_state.compute_buffers[index] = buffer;
|
||||
inline void SetSamplerState(size_t stage, MTL::SamplerState* sampler_state, size_t index) {
|
||||
auto& bound_sampler_state = render_state.sampler_states[stage][index];
|
||||
if (sampler_state != bound_sampler_state.sampler_state) {
|
||||
bound_sampler_state = {true, sampler_state};
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetVertexTexture(MTL::Texture* texture, size_t index) {
|
||||
if (texture != render_state.vertex_textures[index]) {
|
||||
GetRenderCommandEncoder()->setVertexTexture(texture, index);
|
||||
render_state.vertex_textures[index] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetFragmentTexture(MTL::Texture* texture, size_t index) {
|
||||
if (texture != render_state.fragment_textures[index]) {
|
||||
GetRenderCommandEncoder()->setFragmentTexture(texture, index);
|
||||
render_state.fragment_textures[index] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetComputeTexture(MTL::Texture* texture, size_t index) {
|
||||
if (texture != render_state.compute_textures[index]) {
|
||||
GetComputeCommandEncoder()->setTexture(texture, index);
|
||||
render_state.compute_textures[index] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetVertexSamplerState(MTL::SamplerState* sampler_state, size_t index) {
|
||||
if (sampler_state != render_state.vertex_sampler_states[index]) {
|
||||
GetRenderCommandEncoder()->setVertexSamplerState(sampler_state, index);
|
||||
render_state.vertex_sampler_states[index] = sampler_state;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetFragmentSamplerState(MTL::SamplerState* sampler_state, size_t index) {
|
||||
if (sampler_state != render_state.fragment_sampler_states[index]) {
|
||||
GetRenderCommandEncoder()->setFragmentSamplerState(sampler_state, index);
|
||||
render_state.fragment_sampler_states[index] = sampler_state;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetComputeSamplerState(MTL::SamplerState* sampler_state, size_t index) {
|
||||
if (sampler_state != render_state.compute_sampler_states[index]) {
|
||||
GetComputeCommandEncoder()->setSamplerState(sampler_state, index);
|
||||
render_state.compute_sampler_states[index] = sampler_state;
|
||||
}
|
||||
inline void SetIndexBuffer(MTL::Buffer* buffer, size_t offset, IndexFormat index_format,
|
||||
PrimitiveTopology primitive_topology, u32 num_indices,
|
||||
u32 base_vertex) {
|
||||
// TODO: convert parameters to Metal enums
|
||||
render_state.bound_index_buffer = {
|
||||
buffer, offset, MTL::IndexTypeUInt32, MTL::PrimitiveTypeTriangle,
|
||||
num_indices, base_vertex};
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -58,70 +58,146 @@ GraphicsPipeline::GraphicsPipeline(const Device& device_, CommandRecorder& comma
|
|||
}
|
||||
|
||||
void GraphicsPipeline::Configure(bool is_indexed) {
|
||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||
|
||||
texture_cache.SynchronizeGraphicsDescriptors();
|
||||
|
||||
// Find resources
|
||||
size_t stage = 4;
|
||||
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
|
||||
const auto read_handle{[&](const auto& desc, u32 index) {
|
||||
ASSERT(cbufs[desc.cbuf_index].enabled);
|
||||
const u32 index_offset{index << desc.size_shift};
|
||||
const u32 offset{desc.cbuf_offset + index_offset};
|
||||
const GPUVAddr addr{cbufs[desc.cbuf_index].address + offset};
|
||||
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> ||
|
||||
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) {
|
||||
if (desc.has_secondary) {
|
||||
ASSERT(cbufs[desc.secondary_cbuf_index].enabled);
|
||||
const u32 second_offset{desc.secondary_cbuf_offset + index_offset};
|
||||
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address +
|
||||
second_offset};
|
||||
const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left};
|
||||
const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr)
|
||||
<< desc.secondary_shift_left};
|
||||
const u32 raw{lhs_raw | rhs_raw};
|
||||
|
||||
return TexturePair(raw, false);
|
||||
}
|
||||
}
|
||||
auto a = gpu_memory->Read<u32>(addr);
|
||||
// HACK: this particular texture breaks SMO
|
||||
if (a == 310378931)
|
||||
a = 310378932;
|
||||
|
||||
return TexturePair(a, false);
|
||||
}};
|
||||
|
||||
const Shader::Info& info{stage_infos[stage]};
|
||||
|
||||
std::array<VideoCommon::ImageViewInOut, 32> views;
|
||||
std::array<VideoCommon::SamplerId, 32> samplers;
|
||||
size_t view_index{};
|
||||
size_t sampler_index{};
|
||||
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
views[view_index++] = {handle.first};
|
||||
|
||||
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
|
||||
samplers[sampler_index++] = sampler;
|
||||
// Find resources
|
||||
const auto& regs{maxwell3d->regs};
|
||||
const bool via_header_index{regs.sampler_binding == Maxwell::SamplerBinding::ViaHeaderBinding};
|
||||
const auto configure_stage{[&](u32 stage) {
|
||||
const Shader::Info& info{stage_infos[stage]};
|
||||
buffer_cache.UnbindGraphicsStorageBuffers(stage);
|
||||
size_t ssbo_index{};
|
||||
for (const auto& desc : info.storage_buffers_descriptors) {
|
||||
ASSERT(desc.count == 1);
|
||||
buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index,
|
||||
desc.cbuf_offset, desc.is_written);
|
||||
++ssbo_index;
|
||||
}
|
||||
}
|
||||
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
|
||||
const auto read_handle{[&](const auto& desc, u32 index) {
|
||||
ASSERT(cbufs[desc.cbuf_index].enabled);
|
||||
const u32 index_offset{index << desc.size_shift};
|
||||
const u32 offset{desc.cbuf_offset + index_offset};
|
||||
const GPUVAddr addr{cbufs[desc.cbuf_index].address + offset};
|
||||
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> ||
|
||||
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) {
|
||||
if (desc.has_secondary) {
|
||||
ASSERT(cbufs[desc.secondary_cbuf_index].enabled);
|
||||
const u32 second_offset{desc.secondary_cbuf_offset + index_offset};
|
||||
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address +
|
||||
second_offset};
|
||||
const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left};
|
||||
const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr)
|
||||
<< desc.secondary_shift_left};
|
||||
const u32 raw{lhs_raw | rhs_raw};
|
||||
return TexturePair(raw, via_header_index);
|
||||
}
|
||||
}
|
||||
auto a = gpu_memory->Read<u32>(addr);
|
||||
// HACK: this particular texture breaks SMO
|
||||
if (a == 310378931)
|
||||
a = 310378932;
|
||||
|
||||
return TexturePair(a, via_header_index);
|
||||
}};
|
||||
const auto add_image{[&](const auto& desc, bool blacklist) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
views[view_index++] = {
|
||||
.index = handle.first,
|
||||
.blacklist = blacklist,
|
||||
.id = {},
|
||||
};
|
||||
}
|
||||
}};
|
||||
/*
|
||||
if constexpr (Spec::has_texture_buffers) {
|
||||
for (const auto& desc : info.texture_buffer_descriptors) {
|
||||
add_image(desc, false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if constexpr (Spec::has_image_buffers) {
|
||||
for (const auto& desc : info.image_buffer_descriptors) {
|
||||
add_image(desc, false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
views[view_index++] = {handle.first};
|
||||
|
||||
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
|
||||
samplers[sampler_index++] = sampler;
|
||||
}
|
||||
}
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
add_image(desc, desc.is_written);
|
||||
}
|
||||
/*
|
||||
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
|
||||
const auto read_handle{[&](const auto& desc, u32 index) {
|
||||
ASSERT(cbufs[desc.cbuf_index].enabled);
|
||||
const u32 index_offset{index << desc.size_shift};
|
||||
const u32 offset{desc.cbuf_offset + index_offset};
|
||||
const GPUVAddr addr{cbufs[desc.cbuf_index].address + offset};
|
||||
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> ||
|
||||
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) {
|
||||
if (desc.has_secondary) {
|
||||
ASSERT(cbufs[desc.secondary_cbuf_index].enabled);
|
||||
const u32 second_offset{desc.secondary_cbuf_offset + index_offset};
|
||||
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address +
|
||||
second_offset};
|
||||
const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left};
|
||||
const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr)
|
||||
<< desc.secondary_shift_left};
|
||||
const u32 raw{lhs_raw | rhs_raw};
|
||||
|
||||
return TexturePair(raw, false);
|
||||
}
|
||||
}
|
||||
auto a = gpu_memory->Read<u32>(addr);
|
||||
// HACK: this particular texture breaks SMO
|
||||
if (a == 310378931)
|
||||
a = 310378932;
|
||||
|
||||
return TexturePair(a, false);
|
||||
}};
|
||||
|
||||
const Shader::Info& info{stage_infos[stage]};
|
||||
|
||||
std::array<VideoCommon::ImageViewInOut, 32> views;
|
||||
std::array<VideoCommon::SamplerId, 32> samplers;
|
||||
size_t view_index{};
|
||||
size_t sampler_index{};
|
||||
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
views[view_index++] = {handle.first};
|
||||
|
||||
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
|
||||
samplers[sampler_index++] = sampler;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}};
|
||||
|
||||
configure_stage(0);
|
||||
configure_stage(4);
|
||||
|
||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||
|
||||
texture_cache.FillGraphicsImageViews<true>(std::span(views.data(), view_index));
|
||||
|
||||
// Begin render pass
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
|
||||
if (!framebuffer) {
|
||||
return;
|
||||
}
|
||||
command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle());
|
||||
|
||||
command_recorder.SetRenderPipelineState(pipeline_state);
|
||||
|
||||
// Bind resources
|
||||
|
||||
// HACK: try to find a texture that we can bind
|
||||
|
@ -131,8 +207,18 @@ void GraphicsPipeline::Configure(bool is_indexed) {
|
|||
ImageView& image_view{texture_cache.GetImageView(views_it->id)};
|
||||
Sampler& sampler{texture_cache.GetSampler(*samplers_it)};
|
||||
|
||||
command_recorder.SetFragmentTexture(image_view.GetHandle(), 0);
|
||||
command_recorder.SetFragmentSamplerState(sampler.GetHandle(), 0);
|
||||
command_recorder.SetTexture(4, image_view.GetHandle(), 0);
|
||||
command_recorder.SetSamplerState(4, sampler.GetHandle(), 0);
|
||||
|
||||
// Begin render pass
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
|
||||
if (!framebuffer) {
|
||||
return;
|
||||
}
|
||||
command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle());
|
||||
|
||||
command_recorder.SetRenderPipelineState(pipeline_state);
|
||||
}
|
||||
|
||||
void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) {
|
||||
|
|
|
@ -272,7 +272,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
|||
std::cout << code << std::endl;
|
||||
MTL::CompileOptions* compile_options = MTL::CompileOptions::alloc()->init();
|
||||
NS::Error* error = nullptr;
|
||||
MTL::Library* library = device.GetDevice()->newLibrary(
|
||||
[[maybe_unused]] MTL::Library* library = device.GetDevice()->newLibrary(
|
||||
NS::String::string(code.c_str(), NS::ASCIIStringEncoding), compile_options, &error);
|
||||
if (error) {
|
||||
LOG_ERROR(Render_Metal, "failed to create library: {}",
|
||||
|
@ -280,11 +280,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
|||
// HACK
|
||||
std::cout << error->description()->cString(NS::ASCIIStringEncoding) << std::endl;
|
||||
// HACK
|
||||
throw;
|
||||
// throw;
|
||||
}
|
||||
|
||||
functions[index - 1] =
|
||||
library->newFunction(NS::String::string("main_", NS::ASCIIStringEncoding));
|
||||
// functions[stage_index] =
|
||||
// library->newFunction(NS::String::string("main_", NS::ASCIIStringEncoding));
|
||||
previous_stage = &program;
|
||||
}
|
||||
|
||||
|
@ -316,8 +316,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
|||
return out;
|
||||
}
|
||||
|
||||
fragment float4 fragmentMain(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler samplr [[sampler(0)]]) {
|
||||
return tex.sample(samplr, in.texCoord);
|
||||
fragment float4 fragmentMain(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]],
|
||||
sampler samplr [[sampler(0)]]) { return tex.sample(samplr, in.texCoord);
|
||||
}
|
||||
)",
|
||||
NS::ASCIIStringEncoding),
|
||||
|
|
|
@ -42,18 +42,20 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
|
|||
render_pass_descriptor->colorAttachments()->object(0)->setTexture(
|
||||
swap_chain.GetDrawableTexture());
|
||||
|
||||
command_recorder.BeginOrContinueRenderPass(render_pass_descriptor);
|
||||
|
||||
// Blit the framebuffer to the drawable texture
|
||||
// Bind the source texture
|
||||
// TODO: acquire the texture from @ref framebuffers
|
||||
const Framebuffer* const framebuffer = rasterizer.texture_cache.GetFramebuffer();
|
||||
if (!framebuffer) {
|
||||
return;
|
||||
}
|
||||
MTL::Texture* src_texture = framebuffer->GetHandle()->colorAttachments()->object(0)->texture();
|
||||
command_recorder.SetTexture(4, src_texture, 0);
|
||||
command_recorder.SetSamplerState(4, blit_sampler_state, 0);
|
||||
|
||||
command_recorder.BeginOrContinueRenderPass(render_pass_descriptor);
|
||||
|
||||
// Blit the framebuffer to the drawable texture
|
||||
command_recorder.SetRenderPipelineState(blit_pipeline_state);
|
||||
command_recorder.SetFragmentTexture(src_texture, 0);
|
||||
command_recorder.SetFragmentSamplerState(blit_sampler_state, 0);
|
||||
|
||||
// Draw a full screen triangle which will get clipped to a rectangle
|
||||
command_recorder.GetRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeTriangle,
|
||||
|
|
Loading…
Reference in a new issue