mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-01 21:44:17 +01:00
do vertex buffer restride in a void vertex function
This commit is contained in:
parent
5e9537c777
commit
27925a4fd9
@ -1,7 +1,10 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#include "Metal/MTLResource.hpp"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalHybridComputePipeline.h"
|
||||
#include "Common/precompiled.h"
|
||||
#include "Foundation/NSRange.hpp"
|
||||
#include "Metal/MTLRenderCommandEncoder.hpp"
|
||||
|
||||
const size_t BUFFER_ALLOCATION_SIZE = 8 * 1024 * 1024;
|
||||
|
||||
@ -93,21 +96,51 @@ MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(MTL::Bu
|
||||
|
||||
if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride)
|
||||
{
|
||||
// TODO: use compute/void vertex function instead
|
||||
size_t newStride = Align(stride, 4);
|
||||
size_t newSize = vertexBufferRange.size / stride * newStride;
|
||||
// TODO: use one big buffer for all restrided buffers
|
||||
restrideInfo.buffer = m_mtlr->GetDevice()->newBuffer(newSize, MTL::StorageModeShared);
|
||||
if (!restrideInfo.buffer || newSize != restrideInfo.buffer->length())
|
||||
{
|
||||
if (restrideInfo.buffer)
|
||||
restrideInfo.buffer->release();
|
||||
// TODO: use one big buffer for all restrided buffers
|
||||
restrideInfo.buffer = m_mtlr->GetDevice()->newBuffer(newSize, MTL::StorageModeShared);
|
||||
}
|
||||
|
||||
uint8* oldPtr = (uint8*)bufferCache->contents() + vertexBufferRange.offset;
|
||||
uint8* newPtr = (uint8*)restrideInfo.buffer->contents();
|
||||
//uint8* oldPtr = (uint8*)bufferCache->contents() + vertexBufferRange.offset;
|
||||
//uint8* newPtr = (uint8*)restrideInfo.buffer->contents();
|
||||
|
||||
for (size_t elem = 0; elem < vertexBufferRange.size / stride; elem++)
|
||||
{
|
||||
memcpy(newPtr + elem * newStride, oldPtr + elem * stride, stride);
|
||||
}
|
||||
// TODO: remove
|
||||
debug_printf("Restrided vertex buffer (old stride: %zu, new stride: %zu, old size: %zu, new size: %zu)\n", stride, newStride, vertexBufferRange.size, newSize);
|
||||
//for (size_t elem = 0; elem < vertexBufferRange.size / stride; elem++)
|
||||
//{
|
||||
// memcpy(newPtr + elem * newStride, oldPtr + elem * stride, stride);
|
||||
//}
|
||||
//debug_printf("Restrided vertex buffer (old stride: %zu, new stride: %zu, old size: %zu, new size: %zu)\n", stride, newStride, vertexBufferRange.size, newSize);
|
||||
|
||||
if (m_mtlr->GetEncoderType() == MetalEncoderType::Render)
|
||||
{
|
||||
auto renderCommandEncoder = static_cast<MTL::RenderCommandEncoder*>(m_mtlr->GetCommandEncoder());
|
||||
|
||||
renderCommandEncoder->setRenderPipelineState(m_restrideBufferPipeline->GetRenderPipelineState());
|
||||
MTL::Buffer* buffers[] = {bufferCache, restrideInfo.buffer};
|
||||
size_t offsets[] = {vertexBufferRange.offset, 0};
|
||||
renderCommandEncoder->setVertexBuffers(buffers, offsets, NS::Range(0, 2));
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 oldStride;
|
||||
uint32 newStride;
|
||||
} strideData = {static_cast<uint32>(stride), static_cast<uint32>(newStride)};
|
||||
renderCommandEncoder->setVertexBytes(&strideData, sizeof(strideData), 2);
|
||||
|
||||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypePoint, NS::UInteger(0), vertexBufferRange.size / stride);
|
||||
|
||||
MTL::Resource* barrierBuffers[] = {restrideInfo.buffer};
|
||||
renderCommandEncoder->memoryBarrier(barrierBuffers, 1, MTL::RenderStageVertex, MTL::RenderStageVertex);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("vertex buffer restride needs an active render encoder\n");
|
||||
cemu_assert_suspicious();
|
||||
}
|
||||
|
||||
restrideInfo.memoryInvalidated = false;
|
||||
restrideInfo.lastStride = newStride;
|
||||
|
@ -80,7 +80,11 @@ public:
|
||||
MetalVertexBufferCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}
|
||||
~MetalVertexBufferCache();
|
||||
|
||||
// Vertex buffer cache
|
||||
void SetRestrideBufferPipeline(class MetalHybridComputePipeline* restrideBufferPipeline)
|
||||
{
|
||||
m_restrideBufferPipeline = restrideBufferPipeline;
|
||||
}
|
||||
|
||||
void TrackVertexBuffer(uint32 bufferIndex, size_t offset, size_t size, MetalRestrideInfo* restrideInfo)
|
||||
{
|
||||
m_bufferRanges[bufferIndex] = MetalVertexBufferRange{offset, size, restrideInfo};
|
||||
@ -101,6 +105,8 @@ public:
|
||||
private:
|
||||
class MetalRenderer* m_mtlr;
|
||||
|
||||
class MetalHybridComputePipeline* m_restrideBufferPipeline = nullptr;
|
||||
|
||||
MetalVertexBufferRange m_bufferRanges[LATTE_MAX_VERTEX_BUFFERS] = {};
|
||||
|
||||
void MemoryRangeChanged(size_t offset, size_t size);
|
||||
@ -112,6 +118,12 @@ public:
|
||||
MetalMemoryManager(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}, m_bufferAllocator(metalRenderer), m_vertexBufferCache(metalRenderer) {}
|
||||
~MetalMemoryManager();
|
||||
|
||||
// Pipelines
|
||||
void SetRestrideBufferPipeline(class MetalHybridComputePipeline* restrideBufferPipeline)
|
||||
{
|
||||
m_vertexBufferCache.SetRestrideBufferPipeline(restrideBufferPipeline);
|
||||
}
|
||||
|
||||
void ResetTemporaryBuffers()
|
||||
{
|
||||
m_bufferAllocator/*s[m_bufferAllocatorIndex]*/.ResetTemporaryBuffers();
|
||||
|
@ -62,8 +62,9 @@ MetalRenderer::MetalRenderer()
|
||||
MTL::Library* utilityLibrary = m_device->newLibrary(NS::String::string(utilityShaderSource, NS::ASCIIStringEncoding), nullptr, &error);
|
||||
if (error)
|
||||
{
|
||||
debug_printf("failed to create present library (error: %s)\n", error->localizedDescription()->utf8String());
|
||||
debug_printf("failed to create utility library (error: %s)\n", error->localizedDescription()->utf8String());
|
||||
error->release();
|
||||
throw;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -98,12 +99,16 @@ MetalRenderer::MetalRenderer()
|
||||
|
||||
// Hybrid pipelines
|
||||
m_copyTextureToTexturePipeline = new MetalHybridComputePipeline(this, utilityLibrary, "vertexCopyTextureToTexture", "kernelCopyTextureToTexture");
|
||||
m_restrideBufferPipeline = new MetalHybridComputePipeline(this, utilityLibrary, "vertexRestrideBuffer", "kernelRestrideBuffer");
|
||||
utilityLibrary->release();
|
||||
|
||||
m_memoryManager->SetRestrideBufferPipeline(m_restrideBufferPipeline);
|
||||
}
|
||||
|
||||
MetalRenderer::~MetalRenderer()
|
||||
{
|
||||
delete m_copyTextureToTexturePipeline;
|
||||
delete m_restrideBufferPipeline;
|
||||
|
||||
m_presentPipelineLinear->release();
|
||||
m_presentPipelineSRGB->release();
|
||||
@ -688,11 +693,6 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
}
|
||||
const auto fetchShader = LatteSHRC_GetActiveFetchShader();
|
||||
|
||||
// Render pipeline state
|
||||
// TODO: use `m_lastUsedFBO` instead of `m_activeFBO`
|
||||
MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetPipelineState(fetchShader, vertexShader, pixelShader, m_state.m_activeFBO, LatteGPUState.contextNew);
|
||||
renderCommandEncoder->setRenderPipelineState(renderPipelineState);
|
||||
|
||||
// Depth stencil state
|
||||
MTL::DepthStencilState* depthStencilState = m_depthStencilCache->GetDepthStencilState(LatteGPUState.contextNew);
|
||||
renderCommandEncoder->setDepthStencilState(depthStencilState);
|
||||
@ -794,6 +794,10 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
}
|
||||
}
|
||||
|
||||
// Render pipeline state
|
||||
MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetPipelineState(fetchShader, vertexShader, pixelShader, m_state.m_activeFBO, LatteGPUState.contextNew);
|
||||
renderCommandEncoder->setRenderPipelineState(renderPipelineState);
|
||||
|
||||
// Uniform buffers, textures and samplers
|
||||
BindStageResources(renderCommandEncoder, vertexShader);
|
||||
BindStageResources(renderCommandEncoder, pixelShader);
|
||||
@ -1308,7 +1312,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
{
|
||||
LatteMRT::GetCurrentFragCoordScale(GET_UNIFORM_DATA_PTR(shader->uniform.loc_fragCoordScale));
|
||||
}
|
||||
// TODO: uncomment?
|
||||
// TODO: uncomment
|
||||
/*
|
||||
if (shader->uniform.loc_verticesPerInstance >= 0)
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
||||
#include "Common/precompiled.h"
|
||||
#include "Metal/MTLCommandBuffer.hpp"
|
||||
#include "Metal/MTLCommandEncoder.hpp"
|
||||
#include "Metal/MTLRenderPass.hpp"
|
||||
|
||||
#define MAX_MTL_BUFFERS 31
|
||||
@ -244,6 +245,16 @@ public:
|
||||
return m_commandBuffers[m_commandBuffers.size() - 1].m_commandBuffer;
|
||||
}
|
||||
|
||||
MTL::CommandEncoder* GetCommandEncoder()
|
||||
{
|
||||
return m_commandEncoder;
|
||||
}
|
||||
|
||||
MetalEncoderType GetEncoderType()
|
||||
{
|
||||
return m_encoderType;
|
||||
}
|
||||
|
||||
MTL::CommandBuffer* GetCommandBuffer();
|
||||
bool CommandBufferCompleted(MTL::CommandBuffer* commandBuffer);
|
||||
void WaitForCommandBufferCompletion(MTL::CommandBuffer* commandBuffer);
|
||||
@ -284,6 +295,7 @@ private:
|
||||
|
||||
// Hybrid pipelines
|
||||
class MetalHybridComputePipeline* m_copyTextureToTexturePipeline;
|
||||
class MetalHybridComputePipeline* m_restrideBufferPipeline;
|
||||
|
||||
// Basic
|
||||
MTL::SamplerState* m_nearestSampler;
|
||||
|
@ -30,8 +30,20 @@ inline const char* utilityShaderSource = \
|
||||
" uint dstSlice;\n" \
|
||||
"};\n" \
|
||||
"\n" \
|
||||
"vertex void vertexCopyTextureToTexture(uint vid [[vertex_id]], texture2d_array<float, access::read> src [[texture(0)]], texture2d_array<float, access::write> dst [[texture(1)]], constant CopyParams& params) {\n" \
|
||||
"vertex void vertexCopyTextureToTexture(uint vid [[vertex_id]], texture2d_array<float, access::read> src [[texture(0)]], texture2d_array<float, access::write> dst [[texture(1)]], constant CopyParams& params [[buffer(0)]]) {\n" \
|
||||
" uint2 coord = uint2(vid % params.width, vid / params.width);\n" \
|
||||
" return dst.write(float4(src.read(coord, params.srcSlice, params.srcMip).r, 0.0, 0.0, 0.0), coord, params.dstSlice, params.dstMip);\n" \
|
||||
"}\n" \
|
||||
"\n" \
|
||||
"struct RestrideParams {\n" \
|
||||
" uint oldStride;\n" \
|
||||
" uint newStride;\n" \
|
||||
"};\n" \
|
||||
"\n" \
|
||||
/* TODO: use uint32? Since that would require less iterations */ \
|
||||
"vertex void vertexRestrideBuffer(uint vid [[vertex_id]], device uint8_t* src [[buffer(0)]], device uint8_t* dst [[buffer(1)]], constant RestrideParams& params [[buffer(2)]]) {\n" \
|
||||
" for (uint32_t i = 0; i < params.oldStride; i++) {\n" \
|
||||
" dst[vid * params.newStride + i] = src[vid * params.oldStride + i];\n" \
|
||||
" }\n" \
|
||||
"}\n" \
|
||||
"\n";
|
||||
|
Loading…
Reference in New Issue
Block a user