diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/pfMetalPipelineCreatable.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/pfMetalPipelineCreatable.h index c09dd945ed..6550631483 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/pfMetalPipelineCreatable.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/pfMetalPipelineCreatable.h @@ -46,4 +46,4 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plMetalPipeline.h" REGISTER_NONCREATABLE(plMetalPipeline); -#endif // pfGLPipelineCreatable_inc +#endif // pfGLPipelineCreatable_inc diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp index 0526b3a3ef..b0e97d9a68 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp @@ -48,27 +48,25 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define CA_PRIVATE_IMPLEMENTATION #define MTL_PRIVATE_IMPLEMENTATION -#include #include "plMetalDevice.h" -#include "plMetalPipeline.h" -#include "ShaderTypes.h" +#include +#include "ShaderTypes.h" #include "hsThread.h" #include "plDrawable/plGBufferGroup.h" -#include "plGImage/plMipmap.h" #include "plGImage/plCubicEnvironmap.h" -#include "plPipeline/plRenderTarget.h" - +#include "plGImage/plMipmap.h" +#include "plMetalPipeline.h" #include "plMetalPipelineState.h" +#include "plPipeline/plRenderTarget.h" matrix_float4x4* hsMatrix2SIMD(const hsMatrix44& src, matrix_float4x4* dst) { if (src.fFlags & hsMatrix44::kIsIdent) { memcpy(dst, &matrix_identity_float4x4, sizeof(float) * 16); - } - else + } else { memcpy(dst, &src.fMap, sizeof(matrix_float4x4)); } @@ -76,7 +74,6 @@ matrix_float4x4* hsMatrix2SIMD(const hsMatrix44& src, matrix_float4x4* dst) return dst; } - bool plMetalDevice::InitDevice() { //FIXME: Should Metal adopt InitDevice like OGL? @@ -89,37 +86,36 @@ void plMetalDevice::Shutdown() hsAssert(0, "Shutdown not implemented for Metal rendering"); } - void plMetalDevice::SetMaxAnsiotropy(uint8_t maxAnsiotropy) { //setup the material pass samplers //load them all at once and then let the shader pick - + if (maxAnsiotropy == 0) maxAnsiotropy = 1; - - if(fSamplerStates[0] != nullptr) { + + if (fSamplerStates[0] != nullptr) { ReleaseSamplerStates(); } - - MTL::SamplerDescriptor *samplerDescriptor = MTL::SamplerDescriptor::alloc()->init(); + + MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init(); samplerDescriptor->setMaxAnisotropy(maxAnsiotropy); samplerDescriptor->setMinFilter(MTL::SamplerMinMagFilterLinear); samplerDescriptor->setMagFilter(MTL::SamplerMinMagFilterLinear); samplerDescriptor->setMipFilter(MTL::SamplerMipFilterLinear); - + samplerDescriptor->setSAddressMode(MTL::SamplerAddressModeRepeat); samplerDescriptor->setTAddressMode(MTL::SamplerAddressModeRepeat); fSamplerStates[0] = fMetalDevice->newSamplerState(samplerDescriptor); - + samplerDescriptor->setSAddressMode(MTL::SamplerAddressModeClampToEdge); samplerDescriptor->setTAddressMode(MTL::SamplerAddressModeRepeat); fSamplerStates[1] = fMetalDevice->newSamplerState(samplerDescriptor); - + samplerDescriptor->setSAddressMode(MTL::SamplerAddressModeRepeat); samplerDescriptor->setTAddressMode(MTL::SamplerAddressModeClampToEdge); fSamplerStates[2] = fMetalDevice->newSamplerState(samplerDescriptor); - + samplerDescriptor->setSAddressMode(MTL::SamplerAddressModeClampToEdge); samplerDescriptor->setTAddressMode(MTL::SamplerAddressModeClampToEdge); fSamplerStates[3] = fMetalDevice->newSamplerState(samplerDescriptor); @@ -131,7 +127,7 @@ void plMetalDevice::SetMSAASampleCount(uint8_t sampleCount) //Plasma has some MSAA levels that don't completely correspond to what Metal can do //Best fit them to levels Metal can do. Once they are best fit see if the hardware //is capable. - + uint8_t actualSampleCount = 1; if (sampleCount == 6) { actualSampleCount = 8; @@ -140,14 +136,14 @@ void plMetalDevice::SetMSAASampleCount(uint8_t sampleCount) } else if (sampleCount == 2) { actualSampleCount = 2; } - + while (actualSampleCount != 1) { if (fMetalDevice->supportsTextureSampleCount(actualSampleCount)) { break; } actualSampleCount /= 2; } - + fSampleCount = actualSampleCount; } @@ -155,19 +151,19 @@ void plMetalDevice::ReleaseSamplerStates() { fSamplerStates[0]->release(); fSamplerStates[0] = nullptr; - + fSamplerStates[1]->release(); fSamplerStates[1] = nullptr; - + fSamplerStates[2]->release(); fSamplerStates[2] = nullptr; - + fSamplerStates[3]->release(); fSamplerStates[3] = nullptr; } -void plMetalDevice::Clear(bool shouldClearColor, simd_float4 clearColor, bool shouldClearDepth, float clearDepth) { - +void plMetalDevice::Clear(bool shouldClearColor, simd_float4 clearColor, bool shouldClearDepth, float clearDepth) +{ //Plasma may clear a target and draw at different times. //This is specifically trouble with the drawable clear //Plasma might clear the drawable, and then go off and do @@ -175,27 +171,26 @@ void plMetalDevice::Clear(bool shouldClearColor, simd_float4 clearColor, bool sh //draw and clear at the same time. So if it's a clear for the //current drawable, remember that and perform the clear when //we're actually drawing to screen. - + if (fCurrentRenderTargetCommandEncoder) { half4 halfClearColor; halfClearColor[0] = clearColor.r; halfClearColor[1] = clearColor.g; halfClearColor[2] = clearColor.b; halfClearColor[3] = clearColor.a; - plMetalDevice::plMetalLinkedPipeline *linkedPipeline = plMetalClearPipelineState(this, shouldClearColor, shouldClearDepth).GetRenderPipelineState(); - - const MTL::RenderPipelineState *pipelineState = linkedPipeline->pipelineState; + plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalClearPipelineState(this, shouldClearColor, shouldClearDepth).GetRenderPipelineState(); + + const MTL::RenderPipelineState* pipelineState = linkedPipeline->pipelineState; CurrentRenderCommandEncoder()->setRenderPipelineState(pipelineState); - + float clearCoords[8] = { -1, -1, 1, -1, -1, 1, - 1, 1 - }; + 1, 1}; float clearDepth = 1.0f; CurrentRenderCommandEncoder()->setDepthStencilState(fNoZReadStencilState); - + CurrentRenderCommandEncoder()->setCullMode(MTL::CullModeNone); CurrentRenderCommandEncoder()->setVertexBytes(&clearCoords, sizeof(clearCoords), 0); CurrentRenderCommandEncoder()->setFragmentBytes(&halfClearColor, sizeof(halfClearColor), 0); @@ -218,18 +213,17 @@ void plMetalDevice::Clear(bool shouldClearColor, simd_float4 clearColor, bool sh } } } - } -void plMetalDevice::BeginNewRenderPass() { - +void plMetalDevice::BeginNewRenderPass() +{ //printf("Beginning new render pass\n"); - + //lazilly create the screen render encoder if it does not yet exist if (!fCurrentOffscreenCommandBuffer && !fCurrentRenderTargetCommandEncoder) { SetRenderTarget(NULL); } - + if (fCurrentRenderTargetCommandEncoder) { //if we have an existing render target, submit it's commands and release it //if we need to come back to this render target, we can always create a new render @@ -238,10 +232,10 @@ void plMetalDevice::BeginNewRenderPass() { fCurrentRenderTargetCommandEncoder->release(); fCurrentRenderTargetCommandEncoder = nil; } - - MTL::RenderPassDescriptor *renderPassDescriptor = MTL::RenderPassDescriptor::renderPassDescriptor(); + + MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::renderPassDescriptor(); renderPassDescriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore); - + if (fCurrentRenderTarget) { renderPassDescriptor->colorAttachments()->object(0)->setClearColor(MTL::ClearColor(fClearRenderTargetColor.x, fClearRenderTargetColor.y, fClearRenderTargetColor.z, fClearRenderTargetColor.w)); if (fShouldClearRenderTarget) { @@ -249,17 +243,17 @@ void plMetalDevice::BeginNewRenderPass() { } else { renderPassDescriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionLoad); } - - if ( fCurrentRenderTarget->GetZDepth() ) { - plMetalRenderTargetRef* deviceTarget= (plMetalRenderTargetRef *)fCurrentRenderTarget->GetDeviceRef(); + + if (fCurrentRenderTarget->GetZDepth()) { + plMetalRenderTargetRef* deviceTarget = (plMetalRenderTargetRef*)fCurrentRenderTarget->GetDeviceRef(); renderPassDescriptor->depthAttachment()->setTexture(deviceTarget->fDepthBuffer); renderPassDescriptor->depthAttachment()->setClearDepth(fClearRenderTargetDepth); renderPassDescriptor->depthAttachment()->setStoreAction(MTL::StoreActionDontCare); renderPassDescriptor->depthAttachment()->setLoadAction(MTL::LoadActionClear); } - + renderPassDescriptor->colorAttachments()->object(0)->setTexture(fCurrentFragmentOutputTexture); - + fCurrentRenderTargetCommandEncoder = fCurrentOffscreenCommandBuffer->renderCommandEncoder(renderPassDescriptor)->retain(); } else { renderPassDescriptor->colorAttachments()->object(0)->setClearColor(MTL::ClearColor(fClearDrawableColor.x, fClearDrawableColor.y, fClearDrawableColor.z, fClearDrawableColor.w)); @@ -268,13 +262,12 @@ void plMetalDevice::BeginNewRenderPass() { } else { renderPassDescriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionLoad); } - + renderPassDescriptor->depthAttachment()->setClearDepth(fClearDrawableDepth); renderPassDescriptor->depthAttachment()->setLoadAction(MTL::LoadActionClear); renderPassDescriptor->depthAttachment()->setTexture(fCurrentDrawableDepthTexture); renderPassDescriptor->depthAttachment()->setStoreAction(MTL::StoreActionDontCare); - - + if (fSampleCount == 1) { if (NeedsPostprocessing()) { renderPassDescriptor->colorAttachments()->object(0)->setTexture(fCurrentUnprocessedOutputTexture); @@ -283,7 +276,7 @@ void plMetalDevice::BeginNewRenderPass() { } } else { renderPassDescriptor->colorAttachments()->object(0)->setTexture(fCurrentFragmentMSAAOutputTexture); - + //if we need postprocessing, output to the main pass texture //otherwise we can go straight to the drawable if (NeedsPostprocessing()) { @@ -291,13 +284,13 @@ void plMetalDevice::BeginNewRenderPass() { } else { renderPassDescriptor->colorAttachments()->object(0)->setResolveTexture(fCurrentFragmentOutputTexture); } - + renderPassDescriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionMultisampleResolve); } - + fCurrentRenderTargetCommandEncoder = fCurrentCommandBuffer->renderCommandEncoder(renderPassDescriptor)->retain(); } - + fCurrentRenderTargetCommandEncoder->setFragmentSamplerStates(fSamplerStates, NS::Range::Make(0, 4)); } @@ -309,10 +302,10 @@ void plMetalDevice::SetRenderTarget(plRenderTarget* target) We used to allow starting new passes on the same drawable but that would break memoryless buffers on Apple Silicon that don't survive between passes. */ - if((!fCurrentRenderTarget && !target) && fCurrentRenderTargetCommandEncoder) { + if ((!fCurrentRenderTarget && !target) && fCurrentRenderTargetCommandEncoder) { return; } - if( fCurrentRenderTargetCommandEncoder ) { + if (fCurrentRenderTargetCommandEncoder) { //if we have an existing render target, submit it's commands and release it //if we need to come back to this render target, we can always create a new render //pass descriptor and submit more commands @@ -320,8 +313,8 @@ void plMetalDevice::SetRenderTarget(plRenderTarget* target) fCurrentRenderTargetCommandEncoder->release(); fCurrentRenderTargetCommandEncoder = nil; } - - if( fCurrentOffscreenCommandBuffer ) { + + if (fCurrentOffscreenCommandBuffer) { if (fCurrentRenderTarget && fCurrentRenderTarget->GetFlags() & plRenderTarget::kIsOffscreen) { //if our target was offscreen, go ahead and blit back. Something will want this data. MTL::BlitCommandEncoder* blitEncoder = fCurrentOffscreenCommandBuffer->blitCommandEncoder(); @@ -337,26 +330,26 @@ void plMetalDevice::SetRenderTarget(plRenderTarget* target) fCurrentOffscreenCommandBuffer->release(); fCurrentOffscreenCommandBuffer = nil; } - + fCurrentRenderTarget = target; - - if ( fCurrentRenderTarget && fShouldClearRenderTarget == false ) { + + if (fCurrentRenderTarget && fShouldClearRenderTarget == false) { // clear if a clear color wasn't already set fClearRenderTargetColor = simd_make_float4(0.0f, 0.0f, 0.0f, 1.0f); fShouldClearRenderTarget = true; fClearRenderTargetDepth = 1.0; } - - if(fCurrentRenderTarget) { - if(!target->GetDeviceRef()) { + + if (fCurrentRenderTarget) { + if (!target->GetDeviceRef()) { fPipeline->MakeRenderTargetRef(target); } - plMetalRenderTargetRef *deviceTarget= (plMetalRenderTargetRef *)target->GetDeviceRef(); + plMetalRenderTargetRef* deviceTarget = (plMetalRenderTargetRef*)target->GetDeviceRef(); fCurrentOffscreenCommandBuffer = fCommandQueue->commandBuffer(); fCurrentOffscreenCommandBuffer->retain(); fCurrentFragmentOutputTexture = deviceTarget->fTexture; - - if(deviceTarget->fDepthBuffer) { + + if (deviceTarget->fDepthBuffer) { fCurrentDepthFormat = MTL::PixelFormatDepth32Float_Stencil8; } else { fCurrentDepthFormat = MTL::PixelFormatInvalid; @@ -368,83 +361,85 @@ void plMetalDevice::SetRenderTarget(plRenderTarget* target) } plMetalDevice::plMetalDevice() -: fErrorMsg(nullptr), - fActiveThread(hsThread::ThisThreadHash()), - fCurrentDrawable(nullptr), - fCommandQueue(nullptr), - fCurrentRenderTargetCommandEncoder(nullptr), - fCurrentDrawableDepthTexture(nullptr), - fCurrentFragmentOutputTexture(nullptr), - fCurrentCommandBuffer(nullptr), - fCurrentOffscreenCommandBuffer(nullptr), - fCurrentRenderTarget(nullptr), - fNewPipelineStateMap(), - fCurrentFragmentMSAAOutputTexture(nullptr), - fCurrentUnprocessedOutputTexture(nullptr), - fGammaLUTTexture(nullptr), - fGammaAdjustState(nullptr), - fBlitCommandBuffer(nullptr), - fBlitCommandEncoder(nullptr) - { + : fErrorMsg(nullptr), + fActiveThread(hsThread::ThisThreadHash()), + fCurrentDrawable(nullptr), + fCommandQueue(nullptr), + fCurrentRenderTargetCommandEncoder(nullptr), + fCurrentDrawableDepthTexture(nullptr), + fCurrentFragmentOutputTexture(nullptr), + fCurrentCommandBuffer(nullptr), + fCurrentOffscreenCommandBuffer(nullptr), + fCurrentRenderTarget(nullptr), + fNewPipelineStateMap(), + fCurrentFragmentMSAAOutputTexture(nullptr), + fCurrentUnprocessedOutputTexture(nullptr), + fGammaLUTTexture(nullptr), + fGammaAdjustState(nullptr), + fBlitCommandBuffer(nullptr), + fBlitCommandEncoder(nullptr) +{ fClearRenderTargetColor = {0.0, 0.0, 0.0, 1.0}; fClearDrawableColor = {0.0, 0.0, 0.0, 1.0}; fSamplerStates[0] = nullptr; - + fMetalDevice = MTL::CreateSystemDefaultDevice(); fCommandQueue = fMetalDevice->newCommandQueue(); - + //set up all the depth stencil states - MTL::DepthStencilDescriptor *depthDescriptor = MTL::DepthStencilDescriptor::alloc()->init(); - + MTL::DepthStencilDescriptor* depthDescriptor = MTL::DepthStencilDescriptor::alloc()->init(); + depthDescriptor->setDepthCompareFunction(MTL::CompareFunctionAlways); depthDescriptor->setDepthWriteEnabled(true); depthDescriptor->setLabel(NS::String::string("No Z Read", NS::UTF8StringEncoding)); fNoZReadStencilState = fMetalDevice->newDepthStencilState(depthDescriptor); - + depthDescriptor->setDepthCompareFunction(MTL::CompareFunctionLessEqual); depthDescriptor->setDepthWriteEnabled(false); depthDescriptor->setLabel(NS::String::string("No Z Write", NS::UTF8StringEncoding)); fNoZWriteStencilState = fMetalDevice->newDepthStencilState(depthDescriptor); - + depthDescriptor->setDepthCompareFunction(MTL::CompareFunctionAlways); depthDescriptor->setDepthWriteEnabled(false); depthDescriptor->setLabel(NS::String::string("No Z Read or Write", NS::UTF8StringEncoding)); fNoZReadOrWriteStencilState = fMetalDevice->newDepthStencilState(depthDescriptor); - + depthDescriptor->setDepthCompareFunction(MTL::CompareFunctionLessEqual); depthDescriptor->setLabel(NS::String::string("Z Read and Write", NS::UTF8StringEncoding)); depthDescriptor->setDepthWriteEnabled(true); fDefaultStencilState = fMetalDevice->newDepthStencilState(depthDescriptor); - + depthDescriptor->setDepthCompareFunction(MTL::CompareFunctionGreaterEqual); depthDescriptor->setLabel(NS::String::string("Reverse Z", NS::UTF8StringEncoding)); depthDescriptor->setDepthWriteEnabled(true); fReverseZStencilState = fMetalDevice->newDepthStencilState(depthDescriptor); - + depthDescriptor->release(); } -void plMetalDevice::SetViewport() { - CurrentRenderCommandEncoder()->setViewport({ (double)fPipeline->GetViewTransform().GetViewPortLeft(), - (double)fPipeline->GetViewTransform().GetViewPortTop(), - (double)fPipeline->GetViewTransform().GetViewPortWidth(), - (double)fPipeline->GetViewTransform().GetViewPortHeight(), - 0.f, 1.f }); +void plMetalDevice::SetViewport() +{ + CurrentRenderCommandEncoder()->setViewport({(double)fPipeline->GetViewTransform().GetViewPortLeft(), + (double)fPipeline->GetViewTransform().GetViewPortTop(), + (double)fPipeline->GetViewTransform().GetViewPortWidth(), + (double)fPipeline->GetViewTransform().GetViewPortHeight(), + 0.f, 1.f}); } -bool plMetalDevice::BeginRender() { +bool plMetalDevice::BeginRender() +{ if (fActiveThread == hsThread::ThisThreadHash()) { return true; } fActiveThread = hsThread::ThisThreadHash(); - + return true; } -static uint32_t IGetBufferFormatSize(uint8_t format) +static uint32_t IGetBufferFormatSize(uint8_t format) { - uint32_t size = sizeof( float ) * 6 + sizeof( uint32_t ) * 2; // Position and normal, and two packed colors + uint32_t size = sizeof(float) * 6 + sizeof(uint32_t) * 2; // Position and normal, and two packed colors switch (format & plGBufferGroup::kSkinWeightMask) { @@ -454,26 +449,26 @@ static uint32_t IGetBufferFormatSize(uint8_t format) size += sizeof(float); break; default: - hsAssert( false, "Invalid skin weight value in IGetBufferFormatSize()" ); + hsAssert(false, "Invalid skin weight value in IGetBufferFormatSize()"); } - size += sizeof( float ) * 3 * plGBufferGroup::CalcNumUVs(format); + size += sizeof(float) * 3 * plGBufferGroup::CalcNumUVs(format); return size; } -void plMetalDevice::SetupVertexBufferRef(plGBufferGroup *owner, uint32_t idx, plMetalDevice::VertexBufferRef *vRef) +void plMetalDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, plMetalDevice::VertexBufferRef* vRef) { uint8_t format = owner->GetVertexFormat(); - + if (format & plGBufferGroup::kSkinIndices) { format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); - format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... + format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... vRef->SetSkinned(true); vRef->SetVolatile(true); } - - uint32_t vertSize = vertSize = IGetBufferFormatSize(format); // vertex stride + + uint32_t vertSize = vertSize = IGetBufferFormatSize(format); // vertex stride uint32_t numVerts = owner->GetVertBufferCount(idx); vRef->fOwner = owner; @@ -489,23 +484,23 @@ void plMetalDevice::SetupVertexBufferRef(plGBufferGroup *owner, uint32_t idx, pl vRef->SetVolatile(vRef->Volatile() || owner->AreVertsVolatile()); vRef->fIndex = idx; - + const uint32_t vertStart = owner->GetVertBufferStart(idx) * vertSize; const uint32_t size = owner->GetVertBufferEnd(idx) * vertSize - vertStart; - + owner->SetVertexBufferRef(idx, vRef); hsRefCnt_SafeUnRef(vRef); } -void plMetalDevice::CheckStaticVertexBuffer(plMetalDevice::VertexBufferRef *vRef, plGBufferGroup *owner, uint32_t idx) +void plMetalDevice::CheckStaticVertexBuffer(plMetalDevice::VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx) { hsAssert(!vRef->Volatile(), "Creating a managed vertex buffer for a volatile buffer ref"); - + if (!vRef->GetBuffer()) { FillVertexBufferRef(vRef, owner, idx); - + // This is currently a no op, but this would let the buffer know it can // unload the system memory copy, since we have a managed version now. owner->PurgeVertBuffer(idx); @@ -517,33 +512,32 @@ void plMetalDevice::FillVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* gr const uint32_t vertSize = ref->fVertexSize; const uint32_t vertStart = group->GetVertBufferStart(idx) * vertSize; const uint32_t size = group->GetVertBufferEnd(idx) * vertSize - vertStart; - - if(ref->GetBuffer()) { + + if (ref->GetBuffer()) { assert(size <= ref->GetBuffer()->length()); } - + if (!size) { return; } - + MTL::Buffer* metalBuffer = fMetalDevice->newBuffer(size, MTL::StorageModeManaged); ref->SetBuffer(metalBuffer); - uint8_t* buffer = (uint8_t*) ref->GetBuffer()->contents(); + uint8_t* buffer = (uint8_t*)ref->GetBuffer()->contents(); if (ref->fData) { memcpy(buffer, ref->fData + vertStart, size); - } - else + } else { hsAssert(0 == vertStart, "Offsets on non-interleaved data not supported"); hsAssert(group->GetVertBufferCount(idx) * vertSize == size, "Trailing dead space on non-interleaved data not supported"); - + uint8_t* ptr = buffer; - const uint32_t vertSmallSize = group->GetVertexLiteStride() - sizeof(hsPoint3) * 2; - uint8_t* srcVPtr = group->GetVertBufferData(idx); + const uint32_t vertSmallSize = group->GetVertexLiteStride() - sizeof(hsPoint3) * 2; + uint8_t* srcVPtr = group->GetVertBufferData(idx); plGBufferColor* const srcCPtr = group->GetColorBufferData(idx); const size_t numCells = group->GetNumCells(idx); @@ -557,27 +551,26 @@ void plMetalDevice::FillVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* gr memcpy(ptr, srcVPtr + cell->fVtxStart, cell->fLength * vertSize); ptr += cell->fLength * vertSize; assert(size <= cell->fLength * vertSize); - } - else + } else { hsStatusMessage("Non interleaved data"); /// Separated, gotta interleave - uint8_t* tempVPtr = srcVPtr + cell->fVtxStart; + uint8_t* tempVPtr = srcVPtr + cell->fVtxStart; plGBufferColor* tempCPtr = srcCPtr + cell->fColorStart; - int j; - for( j = 0; j < cell->fLength; j++ ) + int j; + for (j = 0; j < cell->fLength; j++) { - memcpy( ptr, tempVPtr, sizeof( hsPoint3 ) * 2 ); - ptr += sizeof( hsPoint3 ) * 2; - tempVPtr += sizeof( hsPoint3 ) * 2; + memcpy(ptr, tempVPtr, sizeof(hsPoint3) * 2); + ptr += sizeof(hsPoint3) * 2; + tempVPtr += sizeof(hsPoint3) * 2; - memcpy( ptr, &tempCPtr->fDiffuse, sizeof( uint32_t ) ); - ptr += sizeof( uint32_t ); - memcpy( ptr, &tempCPtr->fSpecular, sizeof( uint32_t ) ); - ptr += sizeof( uint32_t ); + memcpy(ptr, &tempCPtr->fDiffuse, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + memcpy(ptr, &tempCPtr->fSpecular, sizeof(uint32_t)); + ptr += sizeof(uint32_t); - memcpy( ptr, tempVPtr, vertSmallSize ); + memcpy(ptr, tempVPtr, vertSmallSize); ptr += vertSmallSize; tempVPtr += vertSmallSize; tempCPtr++; @@ -587,7 +580,7 @@ void plMetalDevice::FillVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* gr hsAssert((ptr - buffer) == size, "Didn't fill the buffer?"); } - + metalBuffer->release(); /// Unlock and clean up @@ -595,29 +588,29 @@ void plMetalDevice::FillVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* gr ref->SetDirty(false); } -void plMetalDevice::FillVolatileVertexBufferRef(plMetalDevice::VertexBufferRef *ref, plGBufferGroup *group, uint32_t idx) +void plMetalDevice::FillVolatileVertexBufferRef(plMetalDevice::VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) { uint8_t* dst = ref->fData; uint8_t* src = group->GetVertBufferData(idx); - size_t uvChanSize = plGBufferGroup::CalcNumUVs(group->GetVertexFormat()) * sizeof(float) * 3; + size_t uvChanSize = plGBufferGroup::CalcNumUVs(group->GetVertexFormat()) * sizeof(float) * 3; uint8_t numWeights = (group->GetVertexFormat() & plGBufferGroup::kSkinWeightMask) >> 4; for (uint32_t i = 0; i < ref->fCount; ++i) { - memcpy(dst, src, sizeof(hsPoint3)); // pre-pos + memcpy(dst, src, sizeof(hsPoint3)); // pre-pos dst += sizeof(hsPoint3); src += sizeof(hsPoint3); - src += numWeights * sizeof(float); // weights + src += numWeights * sizeof(float); // weights if (group->GetVertexFormat() & plGBufferGroup::kSkinIndices) - src += sizeof(uint32_t); // indices + src += sizeof(uint32_t); // indices - memcpy(dst, src, sizeof(hsVector3)); // pre-normal + memcpy(dst, src, sizeof(hsVector3)); // pre-normal dst += sizeof(hsVector3); src += sizeof(hsVector3); - memcpy(dst, src, sizeof(uint32_t) * 2); // diffuse & specular + memcpy(dst, src, sizeof(uint32_t) * 2); // diffuse & specular dst += sizeof(uint32_t) * 2; src += sizeof(uint32_t) * 2; @@ -628,7 +621,7 @@ void plMetalDevice::FillVolatileVertexBufferRef(plMetalDevice::VertexBufferRef * } } -void plMetalDevice::SetupIndexBufferRef(plGBufferGroup *owner, uint32_t idx, plMetalDevice::IndexBufferRef *iRef) +void plMetalDevice::SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, plMetalDevice::IndexBufferRef* iRef) { uint32_t numIndices = owner->GetIndexBufferCount(idx); iRef->fCount = numIndices; @@ -645,17 +638,17 @@ void plMetalDevice::SetupIndexBufferRef(plGBufferGroup *owner, uint32_t idx, plM iRef->SetVolatile(owner->AreIdxVolatile()); } -void plMetalDevice::CheckIndexBuffer(plMetalDevice::IndexBufferRef *iRef) +void plMetalDevice::CheckIndexBuffer(plMetalDevice::IndexBufferRef* iRef) { - if(!iRef->GetBuffer() && iRef->fCount) { + if (!iRef->GetBuffer() && iRef->fCount) { iRef->SetVolatile(false); - + iRef->SetDirty(true); iRef->SetRebuiltSinceUsed(true); } } -void plMetalDevice::FillIndexBufferRef(plMetalDevice::IndexBufferRef *iRef, plGBufferGroup *owner, uint32_t idx) +void plMetalDevice::FillIndexBufferRef(plMetalDevice::IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx) { uint32_t startIdx = owner->GetIndexBufferStart(idx); uint32_t fullSize = owner->GetIndexBufferCount(idx) * sizeof(uint16_t); @@ -665,61 +658,61 @@ void plMetalDevice::FillIndexBufferRef(plMetalDevice::IndexBufferRef *iRef, plGB { return; } - + iRef->PrepareForWrite(); MTL::Buffer* indexBuffer = iRef->GetBuffer(); - if(!indexBuffer || indexBuffer->length() < fullSize) { + if (!indexBuffer || indexBuffer->length() < fullSize) { indexBuffer = fMetalDevice->newBuffer(fullSize, MTL::ResourceStorageModeManaged); iRef->SetBuffer(indexBuffer); indexBuffer->release(); } - + memcpy(((uint16_t*)indexBuffer->contents()) + startIdx, owner->GetIndexBufferData(idx) + startIdx, size); indexBuffer->didModifyRange(NS::Range(startIdx, size)); iRef->SetDirty(false); } -void plMetalDevice::SetupTextureRef(plBitmap *img, plMetalDevice::TextureRef *tRef) +void plMetalDevice::SetupTextureRef(plBitmap* img, plMetalDevice::TextureRef* tRef) { tRef->fOwner = img; - + plBitmap* imageToCheck = img; - + //if it's a cubic texture, check the first face. The root img will give a false format that will cause us to decode wrong. plCubicEnvironmap* cubicImg = dynamic_cast(img); - if(cubicImg) { + if (cubicImg) { imageToCheck = cubicImg->GetFace(0); } if (imageToCheck->IsCompressed()) { switch (imageToCheck->fDirectXInfo.fCompressionType) { - case plBitmap::DirectXInfo::kDXT1: + case plBitmap::DirectXInfo::kDXT1: tRef->fFormat = MTL::PixelFormatBC1_RGBA; - break; - case plBitmap::DirectXInfo::kDXT5: + break; + case plBitmap::DirectXInfo::kDXT5: tRef->fFormat = MTL::PixelFormatBC3_RGBA; - break; + break; } } else { switch (imageToCheck->fUncompressedInfo.fType) { - case plBitmap::UncompressedInfo::kRGB8888: - tRef->fFormat = MTL::PixelFormatBGRA8Unorm; - break; - case plBitmap::UncompressedInfo::kRGB4444: - //we'll convert this on load to 8 bits per channel - //Metal doesn't support 4 bits per channel on all hardware - tRef->fFormat = MTL::PixelFormatBGRA8Unorm; - break; - case plBitmap::UncompressedInfo::kRGB1555: - tRef->fFormat = MTL::PixelFormatBGR5A1Unorm; - break; - case plBitmap::UncompressedInfo::kInten8: - tRef->fFormat = MTL::PixelFormatR8Uint; - break; - case plBitmap::UncompressedInfo::kAInten88: - tRef->fFormat = MTL::PixelFormatRG8Uint; - break; + case plBitmap::UncompressedInfo::kRGB8888: + tRef->fFormat = MTL::PixelFormatBGRA8Unorm; + break; + case plBitmap::UncompressedInfo::kRGB4444: + //we'll convert this on load to 8 bits per channel + //Metal doesn't support 4 bits per channel on all hardware + tRef->fFormat = MTL::PixelFormatBGRA8Unorm; + break; + case plBitmap::UncompressedInfo::kRGB1555: + tRef->fFormat = MTL::PixelFormatBGR5A1Unorm; + break; + case plBitmap::UncompressedInfo::kInten8: + tRef->fFormat = MTL::PixelFormatR8Uint; + break; + case plBitmap::UncompressedInfo::kAInten88: + tRef->fFormat = MTL::PixelFormatRG8Uint; + break; } } @@ -734,7 +727,7 @@ void plMetalDevice::ReleaseFramebufferObjects() if (fCurrentUnprocessedOutputTexture) fCurrentUnprocessedOutputTexture->release(); fCurrentFragmentOutputTexture = nil; - + if (fGammaAdjustState) fGammaAdjustState->release(); fGammaAdjustState = nil; @@ -748,7 +741,7 @@ void plMetalDevice::SetFramebufferFormat(MTL::PixelFormat format) } } -void plMetalDevice::CheckTexture(plMetalDevice::TextureRef *tRef) +void plMetalDevice::CheckTexture(plMetalDevice::TextureRef* tRef) { if (!tRef->fTexture) { @@ -756,14 +749,14 @@ void plMetalDevice::CheckTexture(plMetalDevice::TextureRef *tRef) } } -uint plMetalDevice::ConfigureAllowedLevels(plMetalDevice::TextureRef *tRef, plMipmap *mipmap) +uint plMetalDevice::ConfigureAllowedLevels(plMetalDevice::TextureRef* tRef, plMipmap* mipmap) { if (mipmap->IsCompressed()) { mipmap->SetCurrLevel(tRef->fLevels); while ((mipmap->GetCurrWidth() | mipmap->GetCurrHeight()) & 0x03) { tRef->fLevels--; - hsAssert(tRef->fLevels >= 0, "How was this ever compressed?" ); - if(tRef->fLevels < 0) { + hsAssert(tRef->fLevels >= 0, "How was this ever compressed?"); + if (tRef->fLevels < 0) { tRef->fLevels = -1; break; } @@ -772,7 +765,7 @@ uint plMetalDevice::ConfigureAllowedLevels(plMetalDevice::TextureRef *tRef, plMi } } -void plMetalDevice::PopulateTexture(plMetalDevice::TextureRef *tRef, plMipmap *img, uint slice) +void plMetalDevice::PopulateTexture(plMetalDevice::TextureRef* tRef, plMipmap* img, uint slice) { if (img->IsCompressed()) { /* @@ -786,17 +779,17 @@ void plMetalDevice::PopulateTexture(plMetalDevice::TextureRef *tRef, plMipmap *i fixed to be consistant. */ #define HACK_LEVEL_SIZE 1 - + #if HACK_LEVEL_SIZE NS::UInteger width = tRef->fTexture->width(); NS::UInteger height = tRef->fTexture->height(); #endif - + if (tRef->fLevels == -1) { hsAssert(1, "Bad texture found"); return; } - + for (int lvl = 0; lvl <= tRef->fLevels; lvl++) { img->SetCurrLevel(lvl); #if HACK_LEVEL_SIZE @@ -806,42 +799,42 @@ void plMetalDevice::PopulateTexture(plMetalDevice::TextureRef *tRef, plMipmap *i NS::UInteger levelWidth = img->GetCurrWidth(); NS::UInteger levelHeight = img->GetCurrHeight(); #endif - + switch (img->fDirectXInfo.fCompressionType) { case plBitmap::DirectXInfo::kDXT1: - tRef->fTexture->replaceRegion(MTL::Region::Make2D(0, 0, levelWidth, levelHeight), img->GetCurrLevel(), slice, img->GetCurrLevelPtr(), levelWidth * 2, 0); + tRef->fTexture->replaceRegion(MTL::Region::Make2D(0, 0, levelWidth, levelHeight), img->GetCurrLevel(), slice, img->GetCurrLevelPtr(), levelWidth * 2, 0); break; case plBitmap::DirectXInfo::kDXT5: - tRef->fTexture->replaceRegion(MTL::Region::Make2D(0, 0, img->GetCurrWidth(), img->GetCurrHeight()), img->GetCurrLevel(), slice, img->GetCurrLevelPtr(), img->GetCurrWidth() * 4, 0); + tRef->fTexture->replaceRegion(MTL::Region::Make2D(0, 0, img->GetCurrWidth(), img->GetCurrHeight()), img->GetCurrLevel(), slice, img->GetCurrLevelPtr(), img->GetCurrWidth() * 4, 0); break; - } + } } } else { for (int lvl = 0; lvl <= tRef->fLevels; lvl++) { img->SetCurrLevel(lvl); - - if(img->GetCurrLevelPtr()) { - if(img->fUncompressedInfo.fType == plBitmap::UncompressedInfo::kRGB4444) { - - struct RGBA4444Component { - unsigned r:4; - unsigned g:4; - unsigned b:4; - unsigned a:4; + + if (img->GetCurrLevelPtr()) { + if (img->fUncompressedInfo.fType == plBitmap::UncompressedInfo::kRGB4444) { + struct RGBA4444Component + { + unsigned r : 4; + unsigned g : 4; + unsigned b : 4; + unsigned a : 4; }; - - RGBA4444Component *in = (RGBA4444Component *)img->GetCurrLevelPtr(); - simd_uint4 *out = (simd_uint4 *) malloc(img->GetCurrHeight() * img->GetCurrWidth() * 4); - - for(int i=0; i<(img->GetCurrWidth() * img->GetCurrHeight()); i++) { + + RGBA4444Component* in = (RGBA4444Component*)img->GetCurrLevelPtr(); + simd_uint4* out = (simd_uint4*)malloc(img->GetCurrHeight() * img->GetCurrWidth() * 4); + + for (int i = 0; i < (img->GetCurrWidth() * img->GetCurrHeight()); i++) { out[i].r = in[i].r; out[i].g = in[i].g; out[i].b = in[i].b; out[i].a = in[i].a; } - + tRef->fTexture->replaceRegion(MTL::Region::Make2D(0, 0, img->GetCurrWidth(), img->GetCurrHeight()), img->GetCurrLevel(), slice, out, img->GetCurrWidth() * 4, 0); - + free(out); } else { tRef->fTexture->replaceRegion(MTL::Region::Make2D(0, 0, img->GetCurrWidth(), img->GetCurrHeight()), img->GetCurrLevel(), slice, img->GetCurrLevelPtr(), img->GetCurrWidth() * 4, 0); @@ -860,62 +853,60 @@ void plMetalDevice::MakeTextureRef(plMetalDevice::TextureRef* tRef, plMipmap* im if (!img->GetImage()) { return; } - - if(tRef->fTexture) { + + if (tRef->fTexture) { tRef->fTexture->release(); } - + tRef->fLevels = img->GetNumLevels() - 1; //FIXME: Is this texture check actually needed //if(!tRef->fTexture) { - ConfigureAllowedLevels(tRef, img); - - bool textureIsValid = tRef->fLevels > 0; - - //texture doesn't exist yet, create it - bool supportsMipMap = tRef->fLevels && textureIsValid; - MTL::TextureDescriptor *descriptor = MTL::TextureDescriptor::texture2DDescriptor(tRef->fFormat, img->GetWidth(), img->GetHeight(), supportsMipMap); - descriptor->setUsage(MTL::TextureUsageShaderRead); + ConfigureAllowedLevels(tRef, img); + + bool textureIsValid = tRef->fLevels > 0; + + //texture doesn't exist yet, create it + bool supportsMipMap = tRef->fLevels && textureIsValid; + MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::texture2DDescriptor(tRef->fFormat, img->GetWidth(), img->GetHeight(), supportsMipMap); + descriptor->setUsage(MTL::TextureUsageShaderRead); //Metal gets mad if we set this with 0, only set it if we know there are mipmaps - if(supportsMipMap) { + if (supportsMipMap) { descriptor->setMipmapLevelCount(tRef->fLevels + 1); } descriptor->setStorageMode(MTL::StorageModeManaged); - - + tRef->fTexture = fMetalDevice->newTexture(descriptor); - PopulateTexture( tRef, img, 0); + PopulateTexture(tRef, img, 0); //} - - + tRef->SetDirty(false); } -void plMetalDevice::MakeCubicTextureRef(plMetalDevice::TextureRef *tRef, plCubicEnvironmap *img) +void plMetalDevice::MakeCubicTextureRef(plMetalDevice::TextureRef* tRef, plCubicEnvironmap* img) { - MTL::TextureDescriptor *descriptor = MTL::TextureDescriptor::textureCubeDescriptor(tRef->fFormat, img->GetFace(0)->GetWidth(), tRef->fLevels != 0); - + MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::textureCubeDescriptor(tRef->fFormat, img->GetFace(0)->GetWidth(), tRef->fLevels != 0); + if (tRef->fLevels != 0) { descriptor->setMipmapLevelCount(tRef->fLevels + 1); } descriptor->setUsage(MTL::TextureUsageShaderRead); - + tRef->fTexture = fMetalDevice->newTexture(descriptor); - + static const uint kFaceMapping[] = { - 1, // kLeftFace - 0, // kRightFace - 4, // kFrontFace - 5, // kBackFace - 2, // kTopFace - 3 // kBottomFace + 1, // kLeftFace + 0, // kRightFace + 4, // kFrontFace + 5, // kBackFace + 2, // kTopFace + 3 // kBottomFace }; for (size_t i = 0; i < 6; i++) { - PopulateTexture( tRef, img->GetFace(i), kFaceMapping[i]); + PopulateTexture(tRef, img->GetFace(i), kFaceMapping[i]); } - + tRef->SetDirty(false); } @@ -928,7 +919,7 @@ void plMetalDevice::SetWorldToCameraMatrix(const hsMatrix44& src) { hsMatrix44 inv; src.GetInverse(&inv); - + hsMatrix2SIMD(src, &fMatrixW2C); hsMatrix2SIMD(inv, &fMatrixC2W); } @@ -937,7 +928,7 @@ void plMetalDevice::SetLocalToWorldMatrix(const hsMatrix44& src) { hsMatrix44 inv; src.GetInverse(&inv); - + hsMatrix2SIMD(src, &fMatrixL2W); hsMatrix2SIMD(inv, &fMatrixW2L); } @@ -946,30 +937,30 @@ void plMetalDevice::CreateNewCommandBuffer(CA::MetalDrawable* drawable) { fCurrentCommandBuffer = fCommandQueue->commandBuffer(); fCurrentCommandBuffer->retain(); - + SetFramebufferFormat(drawable->texture()->pixelFormat()); - + bool depthNeedsRebuild = fCurrentDrawableDepthTexture == nullptr; depthNeedsRebuild |= drawable->texture()->width() != fCurrentDrawableDepthTexture->width() || drawable->texture()->height() != fCurrentDrawableDepthTexture->height(); - + //cache the depth buffer, we'll just clear it every time. - if(depthNeedsRebuild) { - if(fCurrentDrawableDepthTexture) { + if (depthNeedsRebuild) { + if (fCurrentDrawableDepthTexture) { fCurrentDrawableDepthTexture->release(); fCurrentFragmentMSAAOutputTexture->release(); } - - MTL::TextureDescriptor *depthTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, - drawable->texture()->width(), - drawable->texture()->height(), - false); + + MTL::TextureDescriptor* depthTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, + drawable->texture()->width(), + drawable->texture()->height(), + false); if (fMetalDevice->supportsFamily(MTL::GPUFamilyApple1) && fSampleCount == 1) { depthTextureDescriptor->setStorageMode(MTL::StorageModeMemoryless); - } else { + } else { depthTextureDescriptor->setStorageMode(MTL::StorageModePrivate); } depthTextureDescriptor->setUsage(MTL::TextureUsageRenderTarget); - + if (fSampleCount != 1) { //MSSA depth and color output depthTextureDescriptor->setSampleCount(fSampleCount); @@ -977,19 +968,19 @@ void plMetalDevice::CreateNewCommandBuffer(CA::MetalDrawable* drawable) depthTextureDescriptor->setTextureType(MTL::TextureType2DMultisample); if (fMetalDevice->supportsFamily(MTL::GPUFamilyApple1) && fSampleCount == 1) { depthTextureDescriptor->setStorageMode(MTL::StorageModeMemoryless); - } else { + } else { depthTextureDescriptor->setStorageMode(MTL::StorageModePrivate); } fCurrentDrawableDepthTexture = fMetalDevice->newTexture(depthTextureDescriptor); - - MTL::TextureDescriptor *msaaColorTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(drawable->texture()->pixelFormat(), + + MTL::TextureDescriptor* msaaColorTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(drawable->texture()->pixelFormat(), drawable->texture()->width(), drawable->texture()->height(), false); msaaColorTextureDescriptor->setUsage(MTL::TextureUsageRenderTarget); if (fMetalDevice->supportsFamily(MTL::GPUFamilyApple1) && fSampleCount == 1) { msaaColorTextureDescriptor->setStorageMode(MTL::StorageModeMemoryless); - } else { + } else { msaaColorTextureDescriptor->setStorageMode(MTL::StorageModePrivate); } msaaColorTextureDescriptor->setTextureType(MTL::TextureType2DMultisample); @@ -999,7 +990,7 @@ void plMetalDevice::CreateNewCommandBuffer(CA::MetalDrawable* drawable) fCurrentDrawableDepthTexture = fMetalDevice->newTexture(depthTextureDescriptor); } } - + //Do we need to create a unprocessed output texture? //If the depth needs to be rebuilt - we probably need to rebuild this one too if ((fCurrentUnprocessedOutputTexture && depthNeedsRebuild) || (fCurrentUnprocessedOutputTexture == nullptr && NeedsPostprocessing())) { @@ -1009,109 +1000,108 @@ void plMetalDevice::CreateNewCommandBuffer(CA::MetalDrawable* drawable) fCurrentUnprocessedOutputTexture->release(); fCurrentUnprocessedOutputTexture = fMetalDevice->newTexture(mainPassDescriptor); } - + fCurrentDrawable = drawable->retain(); } -void plMetalDevice::StartPipelineBuild(plMetalPipelineRecord& record, std::condition_variable **condOut) { - - __block std::condition_variable *newCondition = new std::condition_variable(); +void plMetalDevice::StartPipelineBuild(plMetalPipelineRecord& record, std::condition_variable** condOut) +{ + __block std::condition_variable* newCondition = new std::condition_variable(); fConditionMap[record] = newCondition; - if(condOut) { + if (condOut) { *condOut = newCondition; } - + if (fNewPipelineStateMap[record] != NULL) { return fNewPipelineStateMap[record]; } - - MTL::Library *library = fMetalDevice->newDefaultLibrary(); - + + MTL::Library* library = fMetalDevice->newDefaultLibrary(); + std::shared_ptr pipelineState = record.state; - + MTL::RenderPipelineDescriptor* descriptor = MTL::RenderPipelineDescriptor::alloc()->init(); descriptor->setLabel(pipelineState->GetDescription()); - + const MTL::Function* vertexFunction = pipelineState->GetVertexFunction(library); const MTL::Function* fragmentFunction = pipelineState->GetFragmentFunction(library); descriptor->setVertexFunction(vertexFunction); descriptor->setFragmentFunction(fragmentFunction); - + descriptor->colorAttachments()->object(0)->setBlendingEnabled(true); pipelineState->ConfigureBlend(descriptor->colorAttachments()->object(0)); - - MTL::VertexDescriptor *vertexDescriptor = MTL::VertexDescriptor::vertexDescriptor(); + + MTL::VertexDescriptor* vertexDescriptor = MTL::VertexDescriptor::vertexDescriptor(); pipelineState->ConfigureVertexDescriptor(vertexDescriptor); descriptor->setVertexDescriptor(vertexDescriptor); descriptor->setDepthAttachmentPixelFormat(record.depthFormat); descriptor->colorAttachments()->object(0)->setPixelFormat(record.colorFormat); - + descriptor->setSampleCount(record.sampleCount); - + NS::Error* error; - fMetalDevice->newRenderPipelineState(descriptor, ^(MTL::RenderPipelineState *pipelineState, NS::Error *error){ + fMetalDevice->newRenderPipelineState(descriptor, ^(MTL::RenderPipelineState* pipelineState, NS::Error* error) { if (error) { //leave the condition in place for now, we don't want to //retry if the shader is defective. the condition will //prevent retries hsAssert(0, error->localizedDescription()->cString(NS::UTF8StringEncoding)); } else { - plMetalLinkedPipeline *linkedPipeline = new plMetalLinkedPipeline(); + plMetalLinkedPipeline* linkedPipeline = new plMetalLinkedPipeline(); linkedPipeline->pipelineState = pipelineState->retain(); linkedPipeline->fragFunction = fragmentFunction; linkedPipeline->vertexFunction = vertexFunction; - + fNewPipelineStateMap[record] = linkedPipeline; //signal that we're done newCondition->notify_all(); } }); - + descriptor->release(); library->release(); } -plMetalDevice::plMetalLinkedPipeline* plMetalDevice::PipelineState(plMetalPipelineState* pipelineState) { - +plMetalDevice::plMetalLinkedPipeline* plMetalDevice::PipelineState(plMetalPipelineState* pipelineState) +{ MTL::PixelFormat depthFormat = fCurrentDepthFormat; MTL::PixelFormat colorFormat = fCurrentFragmentOutputTexture->pixelFormat(); - + plMetalPipelineRecord record = { depthFormat, colorFormat, - CurrentTargetSampleCount() - }; - + CurrentTargetSampleCount()}; + record.state = std::shared_ptr(pipelineState->Clone()); - + plMetalLinkedPipeline* renderState = fNewPipelineStateMap[record]; - + //if it exists, return it, we're done - if(renderState) { + if (renderState) { return renderState; } - + //check and see if we're already building it. If so, wait. //Note: even if it already exists, this lock will be kept, and it will //let us through. This is to prevent race conditions where the render state //was null, but maybe in the time it took us to get here the state compiled. - std::condition_variable *alreadyBuildingCondition = fConditionMap[record]; - if(alreadyBuildingCondition) { + std::condition_variable* alreadyBuildingCondition = fConditionMap[record]; + if (alreadyBuildingCondition) { std::unique_lock lock(fPipelineCreationMtx); alreadyBuildingCondition->wait(lock); - + //should be returning the render state here, if not it failed to build //we'll allow the null return return fNewPipelineStateMap[record]; } - + //it doesn't exist, start a build and wait //only render thread is allowed to start builds, //shouldn't be race conditions here StartPipelineBuild(record, &alreadyBuildingCondition); std::unique_lock lock(fPipelineCreationMtx); alreadyBuildingCondition->wait(lock); - + //should be returning the render state here, if not it failed to build //we'll allow the null return return fNewPipelineStateMap[record]; @@ -1121,34 +1111,34 @@ std::condition_variable* plMetalDevice::PrewarmPipelineStateFor(plMetalPipelineS { MTL::PixelFormat depthFormat = fCurrentDepthFormat; MTL::PixelFormat colorFormat = fCurrentFragmentOutputTexture->pixelFormat(); - + plMetalPipelineRecord record = { depthFormat, colorFormat, - CurrentTargetSampleCount() - }; - + CurrentTargetSampleCount()}; + record.state = std::shared_ptr(pipelineState->Clone()); //only render thread is allowed to prewarm, no race conditions around //fConditionMap creation - if(!fNewPipelineStateMap[record] && fConditionMap[record]) { - std::condition_variable *condOut; + if (!fNewPipelineStateMap[record] && fConditionMap[record]) { + std::condition_variable* condOut; StartPipelineBuild(record, &condOut); return condOut; } return nullptr; } -bool plMetalDevice::plMetalPipelineRecord::operator==(const plMetalPipelineRecord &p) const { +bool plMetalDevice::plMetalPipelineRecord::operator==(const plMetalPipelineRecord& p) const +{ return depthFormat == p.depthFormat && - colorFormat == p.colorFormat && - sampleCount == p.sampleCount && - state->operator==(*p.state); + colorFormat == p.colorFormat && + sampleCount == p.sampleCount && + state->operator==(*p.state); } MTL::CommandBuffer* plMetalDevice::GetCurrentCommandBuffer() { - if(fCurrentOffscreenCommandBuffer) { + if (fCurrentOffscreenCommandBuffer) { return fCurrentOffscreenCommandBuffer; } return fCurrentCommandBuffer; @@ -1159,30 +1149,30 @@ void plMetalDevice::SubmitCommandBuffer() if (fBlitCommandEncoder) { fBlitCommandEncoder->endEncoding(); fBlitCommandBuffer->commit(); - + fBlitCommandBuffer->release(); fBlitCommandEncoder->release(); - + fBlitCommandBuffer = nullptr; fBlitCommandEncoder = nullptr; } - + fCurrentRenderTargetCommandEncoder->endEncoding(); fCurrentRenderTargetCommandEncoder->release(); fCurrentRenderTargetCommandEncoder = nil; - - if( NeedsPostprocessing() ) { + + if (NeedsPostprocessing()) { PostprocessIntoDrawable(); } - + fCurrentCommandBuffer->presentDrawable(fCurrentDrawable); fCurrentCommandBuffer->commit(); fCurrentCommandBuffer->release(); fCurrentCommandBuffer = nil; - + fCurrentDrawable->release(); fCurrentDrawable = nil; - + // Reset the clear colors for the next pass // Metal clears on framebuffer load - so don't cause a clear // command in this pass to affect the next pass. @@ -1199,46 +1189,46 @@ MTL::SamplerState* plMetalDevice::SampleStateForClampFlags(hsGMatState::hsGMatCl return fSamplerStates[sampleState]; } -void plMetalDevice::CreateGammaAdjustState() { - MTL::RenderPipelineDescriptor *gammaDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); - MTL::Library* library = fMetalDevice->newDefaultLibrary(); - +void plMetalDevice::CreateGammaAdjustState() +{ + MTL::RenderPipelineDescriptor* gammaDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); + MTL::Library* library = fMetalDevice->newDefaultLibrary(); + gammaDescriptor->setVertexFunction(library->newFunction(NS::MakeConstantString("gammaCorrectVertex"))->autorelease()); gammaDescriptor->setFragmentFunction(library->newFunction(NS::MakeConstantString("gammaCorrectFragment"))->autorelease()); - + library->release(); - + gammaDescriptor->colorAttachments()->object(0)->setPixelFormat(fFramebufferFormat); - - NS::Error *error; + + NS::Error* error; fGammaAdjustState->release(); fGammaAdjustState = fMetalDevice->newRenderPipelineState(gammaDescriptor, &error); gammaDescriptor->release(); } -void plMetalDevice::PostprocessIntoDrawable() { - +void plMetalDevice::PostprocessIntoDrawable() +{ if (!fGammaAdjustState) { CreateGammaAdjustState(); } - + //Gamma adjust MTL::RenderPassDescriptor* gammaPassDescriptor = MTL::RenderPassDescriptor::renderPassDescriptor(); gammaPassDescriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionDontCare); gammaPassDescriptor->colorAttachments()->object(0)->setTexture(fCurrentDrawable->texture()); gammaPassDescriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore); - + MTL::RenderCommandEncoder* gammaAdjustEncoder = fCurrentCommandBuffer->renderCommandEncoder(gammaPassDescriptor); - + gammaAdjustEncoder->setRenderPipelineState(fGammaAdjustState); - + static const float fullFrameCoords[16] = { //first pair is vertex, second pair is texture -1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, - 1, 1, 1, 0 - }; + 1, 1, 1, 0}; gammaAdjustEncoder->setVertexBytes(&fullFrameCoords, sizeof(fullFrameCoords), 0); gammaAdjustEncoder->setFragmentTexture(fCurrentUnprocessedOutputTexture, 0); gammaAdjustEncoder->setFragmentTexture(fGammaLUTTexture, 1); @@ -1259,13 +1249,13 @@ MTL::RenderCommandEncoder* plMetalDevice::CurrentRenderCommandEncoder() { //return the current render command encoder //if a framebuffer wasn't set, assume screen, emulating GL - if(fCurrentRenderTargetCommandEncoder) { + if (fCurrentRenderTargetCommandEncoder) { return fCurrentRenderTargetCommandEncoder; } - + if (!fCurrentRenderTargetCommandEncoder) { BeginNewRenderPass(); - + if (fCurrentRenderTarget) { fClearRenderTargetColor = simd_make_float4(0.0f, 0.0f, 0.0f, 1.0f); fShouldClearRenderTarget = false; @@ -1276,7 +1266,7 @@ MTL::RenderCommandEncoder* plMetalDevice::CurrentRenderCommandEncoder() fClearDrawableDepth = 1.0; } } - + return fCurrentRenderTargetCommandEncoder; } @@ -1294,7 +1284,7 @@ void plMetalDevice::BlitTexture(MTL::Texture* src, MTL::Texture* dst) fBlitCommandBuffer->enqueue(); fBlitCommandEncoder = fBlitCommandBuffer->blitCommandEncoder()->retain(); } - + fBlitCommandEncoder->copyFromTexture(src, 0, 0, MTL::Origin(0, 0, 0), MTL::Size(src->width(), src->height(), 0), dst, 0, 0, MTL::Origin(0, 0, 0)); } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h index 089ac3bc61..1598730a45 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h @@ -42,20 +42,17 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef _plMetalDevice_h_ #define _plMetalDevice_h_ -#include "HeadSpin.h" - -#include "hsGMatState.h" - -#include "plMetalDeviceRef.h" -#include "hsMatrix44.h" +#include #include #include -#include - -#include #include +#include +#include "HeadSpin.h" +#include "hsGMatState.h" +#include "hsMatrix44.h" +#include "plMetalDeviceRef.h" #include "plSurface/plShader.h" #include "plSurface/plShaderTable.h" @@ -72,45 +69,44 @@ matrix_float4x4* hsMatrix2SIMD(const hsMatrix44& src, matrix_float4x4* dst); class plMetalDevice { - friend plMetalPipeline; friend class plMetalMaterialShaderRef; friend class plMetalPlateManager; friend class plMetalPipelineState; - -public: + + public: typedef plMetalVertexBufferRef VertexBufferRef; typedef plMetalIndexBufferRef IndexBufferRef; typedef plMetalTextureRef TextureRef; - -public: - plMetalPipeline* fPipeline; - - hsWindowHndl fDevice; - hsWindowHndl fWindow; - - const char* fErrorMsg; - - MTL::RenderCommandEncoder* CurrentRenderCommandEncoder(); - MTL::Device* fMetalDevice; - MTL::CommandQueue* fCommandQueue; - MTL::Buffer* fCurrentIndexBuffer; - - size_t fActiveThread; - matrix_float4x4 fMatrixProj; - matrix_float4x4 fMatrixL2W; - matrix_float4x4 fMatrixW2L; - matrix_float4x4 fMatrixW2C; - matrix_float4x4 fMatrixC2W; - -public: - - struct plMetalLinkedPipeline { - const MTL::RenderPipelineState *pipelineState; - const MTL::Function *fragFunction; - const MTL::Function *vertexFunction; + + public: + plMetalPipeline* fPipeline; + + hsWindowHndl fDevice; + hsWindowHndl fWindow; + + const char* fErrorMsg; + + MTL::RenderCommandEncoder* CurrentRenderCommandEncoder(); + MTL::Device* fMetalDevice; + MTL::CommandQueue* fCommandQueue; + MTL::Buffer* fCurrentIndexBuffer; + + size_t fActiveThread; + matrix_float4x4 fMatrixProj; + matrix_float4x4 fMatrixL2W; + matrix_float4x4 fMatrixW2L; + matrix_float4x4 fMatrixW2C; + matrix_float4x4 fMatrixC2W; + + public: + struct plMetalLinkedPipeline + { + const MTL::RenderPipelineState* pipelineState; + const MTL::Function* fragFunction; + const MTL::Function* vertexFunction; }; - + plMetalDevice(); bool InitDevice(); @@ -128,9 +124,8 @@ class plMetalDevice /** Translate our viewport into a GL viewport. */ void SetViewport(); - bool BeginRender(); - + /* Device Ref Functions **************************************************/ void SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef); void CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx); @@ -144,125 +139,125 @@ class plMetalDevice void CheckTexture(TextureRef* tRef); void MakeTextureRef(TextureRef* tRef, plMipmap* img); void MakeCubicTextureRef(TextureRef* tRef, plCubicEnvironmap* img); - - + const char* GetErrorString() const { return fErrorMsg; } - + void SetProjectionMatrix(const hsMatrix44& src); void SetWorldToCameraMatrix(const hsMatrix44& src); void SetLocalToWorldMatrix(const hsMatrix44& src); - - void PopulateTexture(plMetalDevice::TextureRef *tRef, plMipmap *img, uint slice); - uint ConfigureAllowedLevels(plMetalDevice::TextureRef *tRef, plMipmap *mipmap); - + + void PopulateTexture(plMetalDevice::TextureRef* tRef, plMipmap* img, uint slice); + uint ConfigureAllowedLevels(plMetalDevice::TextureRef* tRef, plMipmap* mipmap); + //stencil states are expensive to make, they should be cached //FIXME: There should be a function to pair these with hsGMatState - MTL::DepthStencilState *fNoZReadStencilState; - MTL::DepthStencilState *fNoZWriteStencilState; - MTL::DepthStencilState *fNoZReadOrWriteStencilState; - MTL::DepthStencilState *fReverseZStencilState; - MTL::DepthStencilState *fDefaultStencilState; - uint8_t fSampleCount; - + MTL::DepthStencilState* fNoZReadStencilState; + MTL::DepthStencilState* fNoZWriteStencilState; + MTL::DepthStencilState* fNoZReadOrWriteStencilState; + MTL::DepthStencilState* fReverseZStencilState; + MTL::DepthStencilState* fDefaultStencilState; + uint8_t fSampleCount; + ///Create a new command buffer to encode all the operations needed to draw a frame //Currently requires a CA drawable and not a Metal drawable. In since CA drawable is only abstract implementation I know about, not sure where we would find others? - void CreateNewCommandBuffer(CA::MetalDrawable* drawable); + void CreateNewCommandBuffer(CA::MetalDrawable* drawable); MTL::CommandBuffer* GetCurrentCommandBuffer(); - CA::MetalDrawable* GetCurrentDrawable(); + CA::MetalDrawable* GetCurrentDrawable(); ///Submit the command buffer to the GPU and draws all the render passes. Clears the current command buffer. - void SubmitCommandBuffer(); - void Clear(bool shouldClearColor, simd_float4 clearColor, bool shouldClearDepth, float clearDepth); - + void SubmitCommandBuffer(); + void Clear(bool shouldClearColor, simd_float4 clearColor, bool shouldClearDepth, float clearDepth); + void SetMaxAnsiotropy(uint8_t maxAnsiotropy); void SetMSAASampleCount(uint8_t sampleCount); - + MTL::SamplerState* SampleStateForClampFlags(hsGMatState::hsGMatClampFlags sampleState); - - NS::UInteger CurrentTargetSampleCount() { + + NS::UInteger CurrentTargetSampleCount() + { if (fCurrentRenderTarget) { return 1; } else { return fSampleCount; } } - + void BlitTexture(MTL::Texture* src, MTL::Texture* dst); - + void EncodeBlur(MTL::CommandBuffer* commandBuffer, MTL::Texture* texture, float sigma); - + MTL::PixelFormat GetFramebufferFormat() { return fFramebufferFormat; }; - -private: - - struct plMetalPipelineRecord { - MTL::PixelFormat depthFormat; - MTL::PixelFormat colorFormat; - NS::UInteger sampleCount; + + private: + struct plMetalPipelineRecord + { + MTL::PixelFormat depthFormat; + MTL::PixelFormat colorFormat; + NS::UInteger sampleCount; std::shared_ptr state; - - bool operator==(const plMetalPipelineRecord &p) const; + + bool operator==(const plMetalPipelineRecord& p) const; }; - - + struct plMetalPipelineRecordHashFunction { std::size_t operator()(plMetalPipelineRecord const& s) const noexcept; }; - - std::unordered_map fNewPipelineStateMap; + + std::unordered_map fNewPipelineStateMap; //the condition map allows consumers of pipeline states to wait until the pipeline state is ready - std::unordered_map fConditionMap; - std::mutex fPipelineCreationMtx; - void StartPipelineBuild(plMetalPipelineRecord& record, std::condition_variable **condOut); - std::condition_variable* PrewarmPipelineStateFor(plMetalPipelineState* pipelineState); - -protected: + std::unordered_map fConditionMap; + std::mutex fPipelineCreationMtx; + void StartPipelineBuild(plMetalPipelineRecord& record, std::condition_variable** condOut); + std::condition_variable* PrewarmPipelineStateFor(plMetalPipelineState* pipelineState); + + protected: plMetalLinkedPipeline* PipelineState(plMetalPipelineState* pipelineState); - + MTL::Texture* fGammaLUTTexture; - + void SetFramebufferFormat(MTL::PixelFormat format); - -private: - MTL::PixelFormat fFramebufferFormat; - + + private: + MTL::PixelFormat fFramebufferFormat; + //these are internal bits for backing the current render pass //private because the functions should be used to keep a consistant //render pass state - MTL::CommandBuffer* fCurrentCommandBuffer; - MTL::CommandBuffer* fCurrentOffscreenCommandBuffer; - MTL::RenderCommandEncoder* fCurrentRenderTargetCommandEncoder; - - MTL::Texture* fCurrentDrawableDepthTexture; - MTL::Texture* fCurrentFragmentOutputTexture; - MTL::Texture* fCurrentUnprocessedOutputTexture; - MTL::Texture* fCurrentFragmentMSAAOutputTexture; - - CA::MetalDrawable* fCurrentDrawable; - MTL::PixelFormat fCurrentDepthFormat; - simd_float4 fClearRenderTargetColor; - simd_float4 fClearDrawableColor; - bool fShouldClearRenderTarget; - bool fShouldClearDrawable; - float fClearRenderTargetDepth; - float fClearDrawableDepth; - plRenderTarget* fCurrentRenderTarget; - MTL::SamplerState* fSamplerStates[4]; - - MTL::CommandBuffer* fBlitCommandBuffer; - MTL::BlitCommandEncoder* fBlitCommandEncoder; - - bool NeedsPostprocessing() { + MTL::CommandBuffer* fCurrentCommandBuffer; + MTL::CommandBuffer* fCurrentOffscreenCommandBuffer; + MTL::RenderCommandEncoder* fCurrentRenderTargetCommandEncoder; + + MTL::Texture* fCurrentDrawableDepthTexture; + MTL::Texture* fCurrentFragmentOutputTexture; + MTL::Texture* fCurrentUnprocessedOutputTexture; + MTL::Texture* fCurrentFragmentMSAAOutputTexture; + + CA::MetalDrawable* fCurrentDrawable; + MTL::PixelFormat fCurrentDepthFormat; + simd_float4 fClearRenderTargetColor; + simd_float4 fClearDrawableColor; + bool fShouldClearRenderTarget; + bool fShouldClearDrawable; + float fClearRenderTargetDepth; + float fClearDrawableDepth; + plRenderTarget* fCurrentRenderTarget; + MTL::SamplerState* fSamplerStates[4]; + + MTL::CommandBuffer* fBlitCommandBuffer; + MTL::BlitCommandEncoder* fBlitCommandEncoder; + + bool NeedsPostprocessing() + { return fGammaLUTTexture != nullptr; } - void PostprocessIntoDrawable(); - void CreateGammaAdjustState(); + void PostprocessIntoDrawable(); + void CreateGammaAdjustState(); MTL::RenderPipelineState* fGammaAdjustState; - + void BeginNewRenderPass(); void ReleaseSamplerStates(); void ReleaseFramebufferObjects(); - + //Blur states std::unordered_map fBlurShaders; }; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevicePerformanceShaders.mm b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevicePerformanceShaders.mm index 888c029799..2760a02ce2 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevicePerformanceShaders.mm +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevicePerformanceShaders.mm @@ -40,46 +40,61 @@ *==LICENSE==*/ -#include -#include "plMetalDevice.h" #include #include +#include +#include "plMetalDevice.h" + +void plMetalDevice::EncodeBlur(MTL::CommandBuffer* commandBuffer, MTL::Texture* texture, + float sigma) { + // FIXME: Blurring currently ends a pass - and restarting a pass will possibly clear one or more + // buffers Technically shadow blurring only happens at the end of the render pass though... + CurrentRenderCommandEncoder()->endEncoding(); + fCurrentRenderTargetCommandEncoder->release(); + fCurrentRenderTargetCommandEncoder = nil; + + // look up the shader by sigma value + MPSImageGaussianBlur* blur = (MPSImageGaussianBlur*)fBlurShaders[sigma]; + + // we don't have one, need to create one + if (!blur) { + blur = [[MPSImageGaussianBlur alloc] initWithDevice:(id)fMetalDevice sigma:sigma]; + fBlurShaders[sigma] = (NS::Object*)blur; + } + + // we'd like to do the blur in place, but Metal might not let us. + // if it allocates a new texture, we'll have to glit that data back to the original + id destTexture = (id)texture; + bool result = + [blur encodeToCommandBuffer:(id)commandBuffer + inPlaceTexture:(id*)&destTexture + fallbackCopyAllocator:^id( + MPSKernel* kernel, id commandBuffer, id texture) { + // this copy allocator will release the original texture - that texture is important, + // don't let it + [texture retain]; + MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::texture2DDescriptor( + (MTL::PixelFormat)texture.pixelFormat, texture.width, texture.height, false); + descriptor->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite); + return (id)fMetalDevice->newTexture(descriptor)->autorelease(); + }]; -void plMetalDevice::EncodeBlur(MTL::CommandBuffer* commandBuffer, MTL::Texture* texture, float sigma) -{ - //FIXME: Blurring currently ends a pass - and restarting a pass will possibly clear one or more buffers - //Technically shadow blurring only happens at the end of the render pass though... - CurrentRenderCommandEncoder()->endEncoding(); - fCurrentRenderTargetCommandEncoder->release(); - fCurrentRenderTargetCommandEncoder = nil; - - //look up the shader by sigma value - MPSImageGaussianBlur *blur = (MPSImageGaussianBlur *)fBlurShaders[sigma]; - - //we don't have one, need to create one - if (!blur) { - blur = [[MPSImageGaussianBlur alloc] initWithDevice:(id)fMetalDevice sigma:sigma]; - fBlurShaders[sigma] = (NS::Object*)blur; - } - - //we'd like to do the blur in place, but Metal might not let us. - //if it allocates a new texture, we'll have to glit that data back to the original - id destTexture = (id)texture; - bool result = [blur encodeToCommandBuffer:(id)commandBuffer inPlaceTexture:(id*)&destTexture fallbackCopyAllocator:^ id (MPSKernel * kernel, id commandBuffer, id texture) { - //this copy allocator will release the original texture - that texture is important, don't let it - [texture retain]; - MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::texture2DDescriptor((MTL::PixelFormat)texture.pixelFormat, texture.width, texture.height, false); - descriptor->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite); - return (id)fMetalDevice->newTexture(descriptor)->autorelease(); - }]; - - //did Metal change our original texture? - if (destTexture != (id)texture) { - //we'll need to blit the dest texture back to the source - //we just committed a compute pass, buffer should be free for us to create - //a blit encoder - id blitEncoder = [(id)GetCurrentCommandBuffer() blitCommandEncoder]; - [blitEncoder copyFromTexture:destTexture sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(destTexture.width, destTexture.height, 1) toTexture:(id)texture destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; - [blitEncoder endEncoding]; - } + // did Metal change our original texture? + if (destTexture != (id)texture) { + // we'll need to blit the dest texture back to the source + // we just committed a compute pass, buffer should be free for us to create + // a blit encoder + id blitEncoder = + [(id)GetCurrentCommandBuffer() blitCommandEncoder]; + [blitEncoder copyFromTexture:destTexture + sourceSlice:0 + sourceLevel:0 + sourceOrigin:MTLOriginMake(0, 0, 0) + sourceSize:MTLSizeMake(destTexture.width, destTexture.height, 1) + toTexture:(id)texture + destinationSlice:0 + destinationLevel:0 + destinationOrigin:MTLOriginMake(0, 0, 0)]; + [blitEncoder endEncoding]; + } } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.cpp index 772b965ee3..4a9616a0ca 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.cpp @@ -7,9 +7,8 @@ #include "plMetalDeviceRef.h" - - -void plMetalDeviceRef::Unlink() { +void plMetalDeviceRef::Unlink() +{ hsAssert(fBack, "plGLDeviceRef not in list"); if (fNext) @@ -18,10 +17,10 @@ void plMetalDeviceRef::Unlink() { fBack = nullptr; fNext = nullptr; - } -void plMetalDeviceRef::Link(plMetalDeviceRef **back) { +void plMetalDeviceRef::Link(plMetalDeviceRef **back) +{ hsAssert(fNext == nullptr && fBack == nullptr, "Trying to link a plMetalDeviceRef that's already linked"); fNext = *back; @@ -42,7 +41,6 @@ plMetalVertexBufferRef::~plMetalVertexBufferRef() Release(); } - void plMetalVertexBufferRef::Release() { SetDirty(true); @@ -54,26 +52,23 @@ plMetalTextureRef::~plMetalTextureRef() Release(); } - void plMetalTextureRef::Release() { SetDirty(true); } - plMetalIndexBufferRef::~plMetalIndexBufferRef() { Release(); } - void plMetalIndexBufferRef::Release() { SetDirty(true); } - -plMetalRenderTargetRef::~plMetalRenderTargetRef() { +plMetalRenderTargetRef::~plMetalRenderTargetRef() +{ Release(); } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.h index e6d69ca942..8dedad8c5f 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRef.h @@ -42,31 +42,37 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef _plMetalDeviceRef_inc_ #define _plMetalDeviceRef_inc_ -#include "HeadSpin.h" -#include "hsGDeviceRef.h" #include #include +#include "HeadSpin.h" +#include "hsGDeviceRef.h" + class plGBufferGroup; class plBitmap; class plRenderTarget; - class plMetalDeviceRef : public hsGDeviceRef { -protected: + protected: plMetalDeviceRef* fNext; plMetalDeviceRef** fBack; - -public: - void Unlink(); - void Link(plMetalDeviceRef **back); - plMetalDeviceRef* GetNext() { return fNext; } - bool IsLinked() { return fBack != nullptr; } - + + public: + void Unlink(); + void Link(plMetalDeviceRef** back); + plMetalDeviceRef* GetNext() { return fNext; } + bool IsLinked() { return fBack != nullptr; } + bool HasFlag(uint32_t f) const { return 0 != (fFlags & f); } - void SetFlag(uint32_t f, bool on) { if(on) fFlags |= f; else fFlags &= ~f; } - + void SetFlag(uint32_t f, bool on) + { + if (on) + fFlags |= f; + else + fFlags &= ~f; + } + virtual void Release() = 0; plMetalDeviceRef(); @@ -80,77 +86,79 @@ class plMetalDeviceRef : public hsGDeviceRef Because buffers are only stored on write, and no allocations happen within the pool, overhead is kept low for static buffers. Completely static buffers will never expand the pool if they only write once. */ -class plMetalBufferPoolRef : public plMetalDeviceRef { -public: - uint32_t fCurrentFrame; - uint32_t fCurrentPass; - uint32_t fLastWriteFrameTime; - - plMetalBufferPoolRef() : - plMetalDeviceRef(), - fLastWriteFrameTime(0), - fCurrentPass(0), - fCurrentFrame(0), - fBuffer(nullptr) +class plMetalBufferPoolRef : public plMetalDeviceRef +{ + public: + uint32_t fCurrentFrame; + uint32_t fCurrentPass; + uint32_t fLastWriteFrameTime; + + plMetalBufferPoolRef() : plMetalDeviceRef(), + fLastWriteFrameTime(0), + fCurrentPass(0), + fCurrentFrame(0), + fBuffer(nullptr) { } - + //Prepare for write must be called anytime a new pass is going to write a buffer. It moves internal record keeping to reflect that either a new frame or new pass is about to write to the pool. - void PrepareForWrite() { + void PrepareForWrite() + { //if we've moved frames since the last time a write happened, reset our current pass index to 0, otherwise increment the current pass - if(fLastWriteFrameTime != fFrameTime) { + if (fLastWriteFrameTime != fFrameTime) { fCurrentPass = 0; fLastWriteFrameTime = fFrameTime; fCurrentFrame = (++fCurrentFrame % 3); } else { fCurrentPass++; } - + //update the current buffer focused, if the is no buffer to focus set it to null uint32_t currentSize = uint32_t(fBuffers[fCurrentFrame].size()); - if(fCurrentPass < currentSize) { + if (fCurrentPass < currentSize) { fBuffer = fBuffers[fCurrentFrame][fCurrentPass]; } else { fBuffer = nullptr; } } - + static void SetFrameTime(uint32_t frameTime) { fFrameTime = frameTime; }; - + MTL::Buffer* GetBuffer() { return fBuffer; }; - - void SetBuffer(MTL::Buffer* buffer) { + + void SetBuffer(MTL::Buffer* buffer) + { fBuffer = buffer->retain(); uint32_t currentSize = uint32_t(fBuffers[fCurrentFrame].size()); //if the current vector doesn't have enough room for the entry, resize it - if(fCurrentPass >= currentSize) { + if (fCurrentPass >= currentSize) { fBuffers[fCurrentFrame].resize(++currentSize); - } else if(fBuffers[fCurrentFrame][fCurrentPass]) { + } else if (fBuffers[fCurrentFrame][fCurrentPass]) { //if we're replacing an existing entry, release the old one fBuffers[fCurrentFrame][fCurrentPass]->release(); } fBuffers[fCurrentFrame][fCurrentPass] = fBuffer; } - - void Release() { - for(int i=0; i<3; i++) { + + void Release() + { + for (int i = 0; i < 3; i++) { for (auto buffer : fBuffers[i]) { buffer->release(); } } fBuffer = nullptr; } - -private: - static uint32_t fFrameTime; - MTL::Buffer* fBuffer; + + private: + static uint32_t fFrameTime; + MTL::Buffer* fBuffer; std::vector fBuffers[3]; }; - class plMetalVertexBufferRef : public plMetalBufferPoolRef { -public: + public: plGBufferGroup* fOwner; uint32_t fCount; uint32_t fIndex; @@ -158,13 +166,14 @@ class plMetalVertexBufferRef : public plMetalBufferPoolRef int32_t fOffset; uint8_t fFormat; uint8_t* fData; - - uint32_t fRefTime; - - enum { - kRebuiltSinceUsed = 0x10, // kDirty = 0x1 is in hsGDeviceRef - kVolatile = 0x20, - kSkinned = 0x40 + + uint32_t fRefTime; + + enum + { + kRebuiltSinceUsed = 0x10, // kDirty = 0x1 is in hsGDeviceRef + kVolatile = 0x20, + kSkinned = 0x40 }; bool RebuiltSinceUsed() const { return HasFlag(kRebuiltSinceUsed); } @@ -178,44 +187,42 @@ class plMetalVertexBufferRef : public plMetalBufferPoolRef bool Expired(uint32_t t) const { return Volatile() && (IsDirty() || (fRefTime != t)); } void SetRefTime(uint32_t t) { fRefTime = t; } - - plMetalVertexBufferRef() : - plMetalBufferPoolRef(), - fCount(0), - fIndex(0), - fVertexSize(0), - fOffset(0), - fOwner(nullptr), - fData(nullptr), - fFormat(0), - fRefTime(0) + + plMetalVertexBufferRef() : plMetalBufferPoolRef(), + fCount(0), + fIndex(0), + fVertexSize(0), + fOffset(0), + fOwner(nullptr), + fData(nullptr), + fFormat(0), + fRefTime(0) { } - + virtual ~plMetalVertexBufferRef(); - - - void Link(plMetalVertexBufferRef** back ) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } - plMetalVertexBufferRef* GetNext() { return (plMetalVertexBufferRef*)fNext; } - + + void Link(plMetalVertexBufferRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } + plMetalVertexBufferRef* GetNext() { return (plMetalVertexBufferRef*)fNext; } + void Release(); }; - class plMetalIndexBufferRef : public plMetalBufferPoolRef { -public: + public: uint32_t fCount; uint32_t fIndex; plGBufferGroup* fOwner; uint32_t fRefTime; uint32_t fLastWriteFrameTime; - - enum { - kRebuiltSinceUsed = 0x10, // kDirty = 0x1 is in hsGDeviceRef - kVolatile = 0x20 + + enum + { + kRebuiltSinceUsed = 0x10, // kDirty = 0x1 is in hsGDeviceRef + kVolatile = 0x20 }; - + bool RebuiltSinceUsed() const { return HasFlag(kRebuiltSinceUsed); } void SetRebuiltSinceUsed(bool b) { SetFlag(kRebuiltSinceUsed, b); } @@ -224,59 +231,55 @@ class plMetalIndexBufferRef : public plMetalBufferPoolRef bool Expired(uint32_t t) const { return Volatile() && (IsDirty() || (fRefTime != t)); } void SetRefTime(uint32_t t) { fRefTime = t; } - + void Release(); - - void Link(plMetalIndexBufferRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } + + void Link(plMetalIndexBufferRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } plMetalIndexBufferRef* GetNext() { return (plMetalIndexBufferRef*)fNext; } virtual ~plMetalIndexBufferRef(); - - plMetalIndexBufferRef(): - plMetalBufferPoolRef(), - fCount(0), - fIndex(0), - fRefTime(0), - fLastWriteFrameTime(0), - fOwner(nullptr) { + + plMetalIndexBufferRef() : plMetalBufferPoolRef(), + fCount(0), + fIndex(0), + fRefTime(0), + fLastWriteFrameTime(0), + fOwner(nullptr) + { } }; - class plMetalTextureRef : public plMetalDeviceRef { -public: - plBitmap* fOwner; - - int32_t fLevels; - MTL::Texture* fTexture; + public: + plBitmap* fOwner; + + int32_t fLevels; + MTL::Texture* fTexture; MTL::PixelFormat fFormat; - - void Link(plMetalTextureRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } - plMetalTextureRef* GetNext() { return (plMetalTextureRef*)fNext; } - - plMetalTextureRef() : - plMetalDeviceRef(), - fOwner(nullptr), - fTexture(nullptr), - fLevels(1) + + void Link(plMetalTextureRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } + plMetalTextureRef* GetNext() { return (plMetalTextureRef*)fNext; } + + plMetalTextureRef() : plMetalDeviceRef(), + fOwner(nullptr), + fTexture(nullptr), + fLevels(1) { } - + virtual ~plMetalTextureRef(); - + void Release(); }; - - -class plMetalRenderTargetRef: public plMetalTextureRef +class plMetalRenderTargetRef : public plMetalTextureRef { -public: - MTL::Texture* fDepthBuffer; + public: + MTL::Texture* fDepthBuffer; + + void Link(plMetalRenderTargetRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } + plMetalRenderTargetRef* GetNext() { return (plMetalRenderTargetRef*)fNext; } - void Link(plMetalRenderTargetRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } - plMetalRenderTargetRef* GetNext() { return (plMetalRenderTargetRef*)fNext; } - plMetalRenderTargetRef() : fDepthBuffer(nullptr) { } @@ -288,6 +291,4 @@ class plMetalRenderTargetRef: public plMetalTextureRef virtual void SetOwner(plRenderTarget* targ) { fOwner = (plBitmap*)targ; } }; - -#endif // _plGLDeviceRef_inc_ - +#endif // _plGLDeviceRef_inc_ diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp index 2dce9f3382..81233adbdc 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp @@ -39,11 +39,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "plPipeline/hsWinRef.h" - -#include "plMetalPipeline.h" #include "plMetalDeviceRef.h" - +#include "plMetalPipeline.h" +#include "plPipeline/hsWinRef.h" #include "plProfile.h" #include "plStatusLog/plStatusLog.h" @@ -51,13 +49,12 @@ plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); plProfile_CreateMemCounter("Indices", "Memory", MemIndex); plProfile_CreateMemCounter("Textures", "Memory", MemTexture); - /***************************************************************************** ** Generic plGLDeviceRef Functions ** *****************************************************************************/ plMetalDeviceRef::plMetalDeviceRef() -: fNext(nullptr), - fBack(nullptr) + : fNext(nullptr), + fBack(nullptr) { } @@ -67,7 +64,8 @@ plMetalDeviceRef::~plMetalDeviceRef() Unlink(); } -void plMetalDeviceRef::Unlink() { +void plMetalDeviceRef::Unlink() +{ hsAssert(fBack, "plGLDeviceRef not in list"); if (fNext) @@ -76,12 +74,12 @@ void plMetalDeviceRef::Unlink() { fBack = nullptr; fNext = nullptr; - } uint32_t plMetalBufferPoolRef::fFrameTime(0); -void plMetalDeviceRef::Link(plMetalDeviceRef **back) { +void plMetalDeviceRef::Link(plMetalDeviceRef **back) +{ hsAssert(fNext == nullptr && fBack == nullptr, "Trying to link a plMetalDeviceRef that's already linked"); fNext = *back; @@ -91,7 +89,6 @@ void plMetalDeviceRef::Link(plMetalDeviceRef **back) { *back = this; } - /***************************************************************************** ** Vertex buffer cleanup Functions ** *****************************************************************************/ @@ -103,13 +100,11 @@ plMetalVertexBufferRef::~plMetalVertexBufferRef() Release(); } - void plMetalVertexBufferRef::Release() { SetDirty(true); } - /***************************************************************************** ** Index buffer cleanup Functions ** *****************************************************************************/ @@ -124,7 +119,6 @@ void plMetalIndexBufferRef::Release() SetDirty(true); } - /***************************************************************************** ** Texture cleanup Functions ** *****************************************************************************/ @@ -141,23 +135,23 @@ void plMetalTextureRef::Release() plMetalTextureRef::~plMetalTextureRef() { Release(); - + if (fNext != nullptr || fBack != nullptr) Unlink(); } - /***************************************************************************** ** FrameBuffer cleanup Functions ** *****************************************************************************/ -plMetalRenderTargetRef::~plMetalRenderTargetRef() { +plMetalRenderTargetRef::~plMetalRenderTargetRef() +{ Release(); } void plMetalRenderTargetRef::Release() { - if(fDepthBuffer) { + if (fDepthBuffer) { fDepthBuffer->release(); fDepthBuffer = nullptr; } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalEnumerate.mm b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalEnumerate.mm index b86372de01..f67485491e 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalEnumerate.mm +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalEnumerate.mm @@ -47,46 +47,48 @@ #include -#include "plMetalPipeline.h" #include +#include "plMetalPipeline.h" -void plMetalEnumerate::Enumerate(std::vector& records) -{ - //For now - just use the default device. If there is a high power discrete device - this will spin it up. - //This will also automatically pin us to an eGPU if present and the user has configured us to use it. - MTL::Device* device = MTL::CreateSystemDefaultDevice(); - - if (device) { - hsG3DDeviceRecord devRec; - devRec.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeMetal); - devRec.SetDriverName("Metal"); - devRec.SetDeviceDesc(device->name()->utf8String()); - //Metal has ways to query capabilities, but doesn't expose a flat version - //Populate with the OS version - @autoreleasepool { - NSProcessInfo *processInfo = [NSProcessInfo processInfo]; - NSOperatingSystemVersion version = processInfo.operatingSystemVersion; - NSString *versionString = [NSString stringWithFormat:@"%li.%li.%li", (long)version.majorVersion, (long)version.minorVersion, version.patchVersion]; - devRec.SetDriverVersion([versionString cStringUsingEncoding:NSUTF8StringEncoding]); - } - devRec.SetDriverDesc(device->name()->utf8String()); - - devRec.SetCap(hsG3DDeviceSelector::kCapsMipmap); - devRec.SetCap(hsG3DDeviceSelector::kCapsPerspective); - devRec.SetCap(hsG3DDeviceSelector::kCapsCompressTextures); - devRec.SetCap(hsG3DDeviceSelector::kCapsDoesSmallTextures); - devRec.SetCap(hsG3DDeviceSelector::kCapsPixelShader); - devRec.SetCap(hsG3DDeviceSelector::kCapsHardware); - - devRec.SetLayersAtOnce(8); - - // Just make a fake mode so the device selector will let it through - hsG3DDeviceMode devMode; - devMode.SetWidth(hsG3DDeviceSelector::kDefaultWidth); - devMode.SetHeight(hsG3DDeviceSelector::kDefaultHeight); - devMode.SetColorDepth(hsG3DDeviceSelector::kDefaultDepth); - devRec.GetModes().emplace_back(devMode); - - records.emplace_back(devRec); +void plMetalEnumerate::Enumerate(std::vector& records) { + // For now - just use the default device. If there is a high power discrete device - this will + // spin it up. This will also automatically pin us to an eGPU if present and the user has + // configured us to use it. + MTL::Device* device = MTL::CreateSystemDefaultDevice(); + + if (device) { + hsG3DDeviceRecord devRec; + devRec.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeMetal); + devRec.SetDriverName("Metal"); + devRec.SetDeviceDesc(device->name()->utf8String()); + // Metal has ways to query capabilities, but doesn't expose a flat version + // Populate with the OS version + @autoreleasepool { + NSProcessInfo* processInfo = [NSProcessInfo processInfo]; + NSOperatingSystemVersion version = processInfo.operatingSystemVersion; + NSString* versionString = + [NSString stringWithFormat:@"%li.%li.%li", (long)version.majorVersion, + (long)version.minorVersion, version.patchVersion]; + devRec.SetDriverVersion([versionString cStringUsingEncoding:NSUTF8StringEncoding]); } + devRec.SetDriverDesc(device->name()->utf8String()); + + devRec.SetCap(hsG3DDeviceSelector::kCapsMipmap); + devRec.SetCap(hsG3DDeviceSelector::kCapsPerspective); + devRec.SetCap(hsG3DDeviceSelector::kCapsCompressTextures); + devRec.SetCap(hsG3DDeviceSelector::kCapsDoesSmallTextures); + devRec.SetCap(hsG3DDeviceSelector::kCapsPixelShader); + devRec.SetCap(hsG3DDeviceSelector::kCapsHardware); + + devRec.SetLayersAtOnce(8); + + // Just make a fake mode so the device selector will let it through + hsG3DDeviceMode devMode; + devMode.SetWidth(hsG3DDeviceSelector::kDefaultWidth); + devMode.SetHeight(hsG3DDeviceSelector::kDefaultHeight); + devMode.SetColorDepth(hsG3DDeviceSelector::kDefaultDepth); + devRec.GetModes().emplace_back(devMode); + + records.emplace_back(devRec); + } } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.cpp index c229751f7f..527b386ba1 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.cpp @@ -39,20 +39,18 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "HeadSpin.h" -#include "hsWindows.h" - -#include - #include "plMetalFragmentShader.h" -#include "plSurface/plShader.h" +#include +#include "HeadSpin.h" +#include "hsWindows.h" #include "plDrawable/plGBufferGroup.h" #include "plMetalPipeline.h" +#include "plSurface/plShader.h" plMetalFragmentShader::plMetalFragmentShader(plShader* owner) -: plMetalShader(owner) + : plMetalShader(owner) { } @@ -70,12 +68,11 @@ void plMetalFragmentShader::Release() bool plMetalFragmentShader::ISetConstants(plMetalPipeline* pipe) { - if( fOwner->GetNumConsts() ) + if (fOwner->GetNumConsts()) { - float *ptr = (float *)fOwner->GetConstBasePtr(); - pipe->GetMetalDevice()->CurrentRenderCommandEncoder()->setFragmentBytes(ptr, fOwner->GetNumConsts() * sizeof(float) * 4, VertexShaderArgumentMaterialShaderUniforms); + float* ptr = (float*)fOwner->GetConstBasePtr(); + pipe->GetMetalDevice()->CurrentRenderCommandEncoder()->setFragmentBytes(ptr, fOwner->GetNumConsts() * sizeof(float) * 4, VertexShaderArgumentMaterialShaderUniforms); } return true; } - diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.h index e9f3fd3f97..b1b99ed7b8 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalFragmentShader.h @@ -50,17 +50,15 @@ class plMetalPipeline; class plMetalFragmentShader : public plMetalShader { -protected: - - -public: - virtual bool ISetConstants(plMetalPipeline* pipe); // On error, sets error string. + protected: + public: + virtual bool ISetConstants(plMetalPipeline* pipe); // On error, sets error string. plMetalFragmentShader(plShader* owner); virtual ~plMetalFragmentShader(); - virtual void Release(); - void Link(plMetalFragmentShader** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } - plMetalFragmentShader* GetNext() { return (plMetalFragmentShader*)fNext; } + virtual void Release(); + void Link(plMetalFragmentShader** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } + plMetalFragmentShader* GetNext() { return (plMetalFragmentShader*)fNext; } }; -#endif // plMetalFragmentShader_inc +#endif // plMetalFragmentShader_inc diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.cpp index c4ef73a418..62b611a102 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.cpp @@ -40,32 +40,29 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ -#include #include "plMetalMaterialShaderRef.h" +#include + #include "HeadSpin.h" #include "hsBitVector.h" - +#include "hsGMatState.inl" #include "plDrawable/plGBufferGroup.h" -#include "plGImage/plMipmap.h" #include "plGImage/plCubicEnvironmap.h" -#include "plPipeline.h" +#include "plGImage/plMipmap.h" +#include "plMetalDevice.h" +#include "plMetalPipeline.h" #include "plPipeDebugFlags.h" +#include "plPipeline.h" #include "plPipeline/plCubicRenderTarget.h" #include "plPipeline/plRenderTarget.h" #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" -#include "hsGMatState.inl" - -#include "plMetalDevice.h" -#include "plMetalPipeline.h" - -plMetalMaterialShaderRef::plMetalMaterialShaderRef(hsGMaterial* mat, plMetalPipeline *pipe) : -fPipeline { pipe }, -fMaterial { mat }, -fFragFunction(), -fNumPasses(0) +plMetalMaterialShaderRef::plMetalMaterialShaderRef(hsGMaterial* mat, plMetalPipeline* pipe) : fPipeline{pipe}, + fMaterial{mat}, + fFragFunction(), + fNumPasses(0) { fDevice = pipe->fDevice.fMetalDevice; fFragFunction = pipe->fFragFunction; @@ -79,18 +76,18 @@ plMetalMaterialShaderRef::~plMetalMaterialShaderRef() void plMetalMaterialShaderRef::Release() { - for(auto & buffer : fPassArgumentBuffers) { + for (auto& buffer : fPassArgumentBuffers) { buffer->release(); buffer = nil; } fPassArgumentBuffers.clear(); - + fNumPasses = 0; } void plMetalMaterialShaderRef::CheckMateralRef() { - if(IsDirty()) { + if (IsDirty()) { /* Something (like avatars) might have modified our textures. If we're dirty - clear all cached state. @@ -99,15 +96,15 @@ void plMetalMaterialShaderRef::CheckMateralRef() fPassIndices.clear(); fPassLengths.clear(); fFragmentShaderDescriptions.clear(); - - for(MTL::Buffer* buffer: fPassArgumentBuffers) { + + for (MTL::Buffer* buffer : fPassArgumentBuffers) { buffer->release(); } fPassArgumentBuffers.clear(); } - if(fNumPasses == 0) { + if (fNumPasses == 0) { ILoopOverLayers(); - + for (size_t i = 0; i < fMaterial->GetNumLayers(); i++) { plLayerInterface* layer = fMaterial->GetLayer(i); if (!layer) { @@ -121,68 +118,70 @@ void plMetalMaterialShaderRef::CheckMateralRef() } //fast encode doesn't support piggybacks or push over layers, but it does use preloaded data on the GPU so it's much faster. Use this encoder if there are no piggybacks or pushover layers -void plMetalMaterialShaderRef::FastEncodeArguments(MTL::RenderCommandEncoder *encoder, VertexUniforms *vertexUniforms, uint pass) +void plMetalMaterialShaderRef::FastEncodeArguments(MTL::RenderCommandEncoder* encoder, VertexUniforms* vertexUniforms, uint pass) { for (uint32_t i = GetPassIndex(pass); i < GetPassIndex(pass) + fPassLengths[pass]; i++) { plLayerInterface* layer = fMaterial->GetLayer(i); - + if (!layer) { continue; } fPipeline->CheckTextureRef(layer); - + plBitmap* img = plBitmap::ConvertNoRef(layer->GetTexture()); if (!img) { continue; } - + plMetalTextureRef* texRef = (plMetalTextureRef*)img->GetDeviceRef(); //if (!texRef->fTexture) { - // continue; + // continue; //} - + assert(i - GetPassIndex(pass) >= 0); EncodeTransform(layer, &vertexUniforms->uvTransforms[i - GetPassIndex(pass)]); IBuildLayerTexture(encoder, i - GetPassIndex(pass), layer); } - + encoder->setFragmentBuffer(fPassArgumentBuffers[pass], 0, FragmentShaderArgumentUniforms); } -void plMetalMaterialShaderRef::EncodeArguments(MTL::RenderCommandEncoder *encoder, VertexUniforms *vertexUniforms, uint pass, plMetalFragmentShaderDescription* passDescription, std::vector *piggyBacks, std::function preEncodeTransform, std::function postEncodeTransform) +void plMetalMaterialShaderRef::EncodeArguments(MTL::RenderCommandEncoder* encoder, VertexUniforms* vertexUniforms, uint pass, plMetalFragmentShaderDescription* passDescription, std::vector* piggyBacks, std::function preEncodeTransform, std::function postEncodeTransform) { - std::vector layers = GetLayersForPass(pass); - - if(piggyBacks) { + + if (piggyBacks) { layers.insert(layers.end(), piggyBacks->begin(), piggyBacks->end()); } - + plMetalFragmentShaderArgumentBuffer uniforms; - - IHandleMaterial(GetPassIndex(pass), passDescription, &uniforms, piggyBacks, - [&](plLayerInterface* layer, uint32_t index) { + + IHandleMaterial( + GetPassIndex(pass), passDescription, &uniforms, piggyBacks, + [&](plLayerInterface* layer, uint32_t index) { layer = preEncodeTransform(layer, index); IBuildLayerTexture(encoder, index, layer); - + plBitmap* img = plBitmap::ConvertNoRef(layer->GetTexture()); - + assert(index - GetPassIndex(pass) >= 0); EncodeTransform(layer, &vertexUniforms->uvTransforms[index]); - + return layer; - }, [&](plLayerInterface* layer, uint32_t index) { + }, + [&](plLayerInterface* layer, uint32_t index) { layer = postEncodeTransform(layer, index); return layer; }); - + encoder->setFragmentBytes(&uniforms, sizeof(plMetalFragmentShaderArgumentBuffer), FragmentShaderArgumentUniforms); } -void plMetalMaterialShaderRef::EncodeTransform(plLayerInterface* layer, UVOutDescriptor *transform) { +void plMetalMaterialShaderRef::EncodeTransform(plLayerInterface* layer, UVOutDescriptor* transform) +{ matrix_float4x4 tXfm; hsMatrix2SIMD(layer->GetTransform(), &tXfm); transform->transform = tXfm; @@ -191,9 +190,8 @@ void plMetalMaterialShaderRef::EncodeTransform(plLayerInterface* layer, UVOutDes //This is old - supporting the plate code. //FIXME: Replace the plate codes path to texturing -void plMetalMaterialShaderRef::prepareTextures(MTL::RenderCommandEncoder *encoder, uint pass) +void plMetalMaterialShaderRef::prepareTextures(MTL::RenderCommandEncoder* encoder, uint pass) { - plLayerInterface* layer = fMaterial->GetLayer(pass); if (!layer) { return; @@ -212,10 +210,10 @@ void plMetalMaterialShaderRef::prepareTextures(MTL::RenderCommandEncoder *encode if (!texRef->fTexture) { return; } - + if (plCubicEnvironmap::ConvertNoRef(layer->GetTexture()) != nullptr) { } else if (plMipmap::ConvertNoRef(layer->GetTexture()) != nullptr || plRenderTarget::ConvertNoRef(layer->GetTexture()) != nullptr) { - encoder->setFragmentTexture(texRef->fTexture, FragmentShaderArgumentTexture); + encoder->setFragmentTexture(texRef->fTexture, FragmentShaderArgumentTexture); } } @@ -223,53 +221,54 @@ void plMetalMaterialShaderRef::ILoopOverLayers() { uint32_t pass = 0; - for (uint32_t j = 0; j < fMaterial->GetNumLayers(); ) + for (uint32_t j = 0; j < fMaterial->GetNumLayers();) { uint32_t currLayer = j; - + //Create "fast encode" buffers //Fast encode can be used when there are no piggybacks or pushover layers. We'll load as much of the //base state of this layer as we can onto the GPU. Using fast encode, the renderer can avoid encoding //a lot of the render state, it will be on the GPU already. //I'd like to encode more data here, and use a heap. The heap hasn't happened yet because heaps are //private memory, and we don't have a window yet for a blit phase into private memory. - MTL::Buffer *argumentBuffer = fDevice->newBuffer(sizeof(plMetalFragmentShaderArgumentBuffer), MTL::ResourceStorageModeManaged); - - plMetalFragmentShaderArgumentBuffer *layerBuffer = (plMetalFragmentShaderArgumentBuffer *)argumentBuffer->contents(); - + MTL::Buffer* argumentBuffer = fDevice->newBuffer(sizeof(plMetalFragmentShaderArgumentBuffer), MTL::ResourceStorageModeManaged); + + plMetalFragmentShaderArgumentBuffer* layerBuffer = (plMetalFragmentShaderArgumentBuffer*)argumentBuffer->contents(); + plMetalFragmentShaderDescription passDescription; - - j = IHandleMaterial(currLayer, &passDescription, layerBuffer, nullptr, - [](plLayerInterface* layer, uint32_t index) { - return layer; - }, - [](plLayerInterface* layer, uint32_t index) { - return layer; - }); + + j = IHandleMaterial( + currLayer, &passDescription, layerBuffer, nullptr, + [](plLayerInterface* layer, uint32_t index) { + return layer; + }, + [](plLayerInterface* layer, uint32_t index) { + return layer; + }); if (j == -1) break; - + passDescription.CacheHash(); fFragmentShaderDescriptions.push_back(passDescription); - + std::vector layers(j); - + pass++; - + //encode the colors for this pass into our buffer for fast rendering - for(int layerOffset = 0; layerOffset < j - currLayer; layerOffset ++) { + for (int layerOffset = 0; layerOffset < j - currLayer; layerOffset++) { plLayerInterface* layer = fMaterial->GetLayer(currLayer + layerOffset); layers[layerOffset] = layer; IBuildLayerTexture(NULL, layerOffset, layer); } - + fPasses.push_back(layers); - + argumentBuffer->didModifyRange(NS::Range(0, argumentBuffer->length())); - + fPassArgumentBuffers.push_back(argumentBuffer); - + fPassIndices.push_back(currLayer); fPassLengths.push_back(j - currLayer); fNumPasses++; @@ -287,18 +286,18 @@ const hsGMatState plMetalMaterialShaderRef::ICompositeLayerState(const plLayerIn return state; } -void plMetalMaterialShaderRef::IBuildLayerTexture(MTL::RenderCommandEncoder *encoder, uint32_t offsetFromRootLayer, plLayerInterface* layer) +void plMetalMaterialShaderRef::IBuildLayerTexture(MTL::RenderCommandEncoder* encoder, uint32_t offsetFromRootLayer, plLayerInterface* layer) { // Reminder: Encoder is allowed to be null when Plasma is precompiling pipeline states // Metal needs to know if a shader is 2D or Cubic to compile shaders // A null encoder signifies we should build the texture but not bind state - + fPipeline->CheckTextureRef(layer); plBitmap* texture = layer->GetTexture(); - + if (texture != nullptr && encoder) { - plMetalTextureRef *deviceTexture = (plMetalTextureRef *)texture->GetDeviceRef(); - if(!deviceTexture) { + plMetalTextureRef* deviceTexture = (plMetalTextureRef*)texture->GetDeviceRef(); + if (!deviceTexture) { //FIXME: Better way to address missing textures than null pointers encoder->setFragmentTexture(nullptr, FragmentShaderArgumentAttributeCubicTextures + offsetFromRootLayer); encoder->setFragmentTexture(nullptr, FragmentShaderArgumentAttributeTextures + offsetFromRootLayer); @@ -310,12 +309,12 @@ void plMetalMaterialShaderRef::IBuildLayerTexture(MTL::RenderCommandEncoder *enc } else if (plMipmap::ConvertNoRef(texture) != nullptr || plRenderTarget::ConvertNoRef(texture) != nullptr) { encoder->setFragmentTexture(deviceTexture->fTexture, FragmentShaderArgumentAttributeTextures + offsetFromRootLayer); } - + if (fPipeline->fState.layerStates[offsetFromRootLayer].clampFlag != layer->GetClampFlags()) { MTL::SamplerState* samplerState = fPipeline->fDevice.SampleStateForClampFlags(hsGMatState::hsGMatClampFlags(layer->GetClampFlags())); encoder->setFragmentSamplerState(samplerState, offsetFromRootLayer); - + fPipeline->fState.layerStates[offsetFromRootLayer].clampFlag = hsGMatState::hsGMatClampFlags(layer->GetClampFlags()); } } @@ -351,7 +350,7 @@ uint32_t plMetalMaterialShaderRef::ILayersAtOnce(uint32_t which) // Ignoring max UVW limit - if ((lay->GetMiscFlags() & hsGMatState::kMiscBindNext) && (i+1 >= maxLayers)) { + if ((lay->GetMiscFlags() & hsGMatState::kMiscBindNext) && (i + 1 >= maxLayers)) { break; } @@ -392,7 +391,7 @@ bool plMetalMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) return true; } -uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragmentShaderDescription *passDescription, plMetalFragmentShaderArgumentBuffer *uniforms, std::vector *piggybacks, std::function preEncodeTransform, std::function postEncodeTransform) +uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragmentShaderDescription* passDescription, plMetalFragmentShaderArgumentBuffer* uniforms, std::vector* piggybacks, std::function preEncodeTransform, std::function postEncodeTransform) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) { return -1; @@ -401,7 +400,7 @@ uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragme if (false /*ISkipBumpMap(fMaterial, layer)*/) { return -1; } - + memset(passDescription, 0, sizeof(plMetalFragmentShaderDescription)); // Ignoring the bit about ATI Radeon and UVW limits @@ -433,20 +432,20 @@ uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragme state.fBlendFlags &= ~hsGMatState::kBlendMask; } - if ((fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpUV) || fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpW)) && (state.fMiscFlags & hsGMatState::kMiscBumpChans) ) { + if ((fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpUV) || fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpW)) && (state.fMiscFlags & hsGMatState::kMiscBumpChans)) { switch (state.fMiscFlags & hsGMatState::kMiscBumpChans) { case hsGMatState::kMiscBumpDu: break; case hsGMatState::kMiscBumpDv: - if (!(fMaterial->GetLayer(layer-2)->GetBlendFlags() & hsGMatState::kBlendAdd)) + if (!(fMaterial->GetLayer(layer - 2)->GetBlendFlags() & hsGMatState::kBlendAdd)) { state.fBlendFlags &= ~hsGMatState::kBlendMask; state.fBlendFlags |= hsGMatState::kBlendMADD; } break; case hsGMatState::kMiscBumpDw: - if (!(fMaterial->GetLayer(layer-1)->GetBlendFlags() & hsGMatState::kBlendAdd)) + if (!(fMaterial->GetLayer(layer - 1)->GetBlendFlags() & hsGMatState::kBlendAdd)) { state.fBlendFlags &= ~hsGMatState::kBlendMask; state.fBlendFlags |= hsGMatState::kBlendMADD; @@ -462,11 +461,11 @@ uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragme if (state.fMiscFlags & (hsGMatState::kMiscBumpDu | hsGMatState::kMiscBumpDw)) { //ISetBumpMatrices(currLay); } - + passDescription->Populate(currLay, 0); - + postEncodeTransform(currLay, 0); - + int32_t i = 1; for (i = 1; i < currNumLayers; i++) { @@ -475,30 +474,29 @@ uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragme return -1; } layPtr = preEncodeTransform(layPtr, i); - - passDescription->Populate(layPtr, i); - + + passDescription->Populate(layPtr, i); + layPtr = postEncodeTransform(layPtr, i); } - - if(piggybacks) { + + if (piggybacks) { for (int32_t currPiggyback = 0; currPiggyback < piggybacks->size(); currPiggyback++) { - plLayerInterface* layPtr = piggybacks->at(currPiggyback); if (!layPtr) { return -1; } layPtr = preEncodeTransform(layPtr, i + currPiggyback); - + passDescription->Populate(layPtr, i + currPiggyback); - + layPtr = postEncodeTransform(layPtr, i + currPiggyback); } } - - passDescription->numLayers = ( piggybacks ? piggybacks->size() : 0 ) + currNumLayers; - + + passDescription->numLayers = (piggybacks ? piggybacks->size() : 0) + currNumLayers; + if (state.fBlendFlags & (hsGMatState::kBlendTest | hsGMatState::kBlendAlpha | hsGMatState::kBlendAddColorTimesAlpha) && !(state.fBlendFlags & hsGMatState::kBlendAlphaAlways)) { @@ -508,13 +506,13 @@ uint32_t plMetalMaterialShaderRef::IHandleMaterial(uint32_t layer, plMetalFragme // some transparency falloff, but quit drawing before it gets so // transparent that draw order problems (halos) become apparent. if (state.fBlendFlags & hsGMatState::kBlendAlphaTestHigh) { - uniforms->alphaThreshold = 64.f/255.f; + uniforms->alphaThreshold = 64.f / 255.f; } else { - uniforms->alphaThreshold = 1.f/255.f; + uniforms->alphaThreshold = 1.f / 255.f; } } else { uniforms->alphaThreshold = 0.f; } - + return layer + currNumLayers; } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.h index 97d69b2585..5c4927cfde 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalMaterialShaderRef.h @@ -42,72 +42,75 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef _plMetalMaterialShaderRef_inc_ #define _plMetalMaterialShaderRef_inc_ +#include +#include + +#include "ShaderTypes.h" #include "hsGMatState.h" #include "plMetalDeviceRef.h" -#include "ShaderTypes.h" #include "plMetalPipelineState.h" -#include -#include - class hsGMaterial; class plMetalPipeline; class plLayerInterface; class plMetalMaterialShaderRef : public plMetalDeviceRef { -protected: - plMetalPipeline* fPipeline; - hsGMaterial* fMaterial; + protected: + plMetalPipeline *fPipeline; + hsGMaterial *fMaterial; //temporary holder for the fragment shader to use, we don't own this reference - MTL::Function* fFragFunction; -private: - std::vector fPassIndices; + MTL::Function *fFragFunction; + + private: + std::vector fPassIndices; //FIXME: This should be retained/released - MTL::Device* fDevice; - std::vector fPassArgumentBuffers; - -public: - void Link(plMetalMaterialShaderRef** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } - plMetalMaterialShaderRef* GetNext() { return (plMetalMaterialShaderRef*)fNext; } - - plMetalMaterialShaderRef(hsGMaterial* mat, plMetalPipeline *pipe); + MTL::Device *fDevice; + std::vector fPassArgumentBuffers; + + public: + void Link(plMetalMaterialShaderRef **back) { plMetalDeviceRef::Link((plMetalDeviceRef **)back); } + plMetalMaterialShaderRef *GetNext() { return (plMetalMaterialShaderRef *)fNext; } + + plMetalMaterialShaderRef(hsGMaterial *mat, plMetalPipeline *pipe); ~plMetalMaterialShaderRef(); - + void Release(); void CheckMateralRef(); - + uint32_t GetNumPasses() const { return fNumPasses; } - - uint32_t GetPassIndex(size_t which) const { return fPassIndices[which]; } + + uint32_t GetPassIndex(size_t which) const { return fPassIndices[which]; } const std::vector GetLayersForPass(size_t pass) { return fPasses[pass]; } - - void EncodeArguments(MTL::RenderCommandEncoder *encoder, VertexUniforms *vertexUniforms, uint pass, plMetalFragmentShaderDescription *passDescription, std::vector *piggyBacks, std::function preEncodeTransform, std::function postEncodeTransform); - void FastEncodeArguments(MTL::RenderCommandEncoder *encoder, VertexUniforms *vertexUniforms, uint pass); + + void EncodeArguments(MTL::RenderCommandEncoder *encoder, VertexUniforms *vertexUniforms, uint pass, plMetalFragmentShaderDescription *passDescription, std::vector *piggyBacks, std::function preEncodeTransform, std::function postEncodeTransform); + void FastEncodeArguments(MTL::RenderCommandEncoder *encoder, VertexUniforms *vertexUniforms, uint pass); //probably not a good idea to call prepareTextures directly //mostly just a hack to keep plates working for now - void prepareTextures(MTL::RenderCommandEncoder *encoder, uint pass); - std::vector fPassLengths; - + void prepareTextures(MTL::RenderCommandEncoder *encoder, uint pass); + std::vector fPassLengths; + // Set the current Plasma state based on the input layer state and the material overrides. // fMatOverOn overrides to set a state bit whether it is set in the layer or not. // fMatOverOff overrides to clear a state bit whether it is set in the layer or not.s - const hsGMatState ICompositeLayerState(const plLayerInterface* layer); - - const struct plMetalFragmentShaderDescription GetFragmentShaderDescription(size_t which) { + const hsGMatState ICompositeLayerState(const plLayerInterface *layer); + + const struct plMetalFragmentShaderDescription GetFragmentShaderDescription(size_t which) + { return fFragmentShaderDescriptions[which]; } -private: + + private: void ILoopOverLayers(); - + uint32_t fNumPasses; - uint32_t IHandleMaterial(uint32_t layer, plMetalFragmentShaderDescription *passDescription, plMetalFragmentShaderArgumentBuffer *uniforms, std::vector *piggybacks, std::function preEncodeTransform, std::function postEncodeTransform); - bool ICanEatLayer(plLayerInterface* lay); + uint32_t IHandleMaterial(uint32_t layer, plMetalFragmentShaderDescription *passDescription, plMetalFragmentShaderArgumentBuffer *uniforms, std::vector *piggybacks, std::function preEncodeTransform, std::function postEncodeTransform); + bool ICanEatLayer(plLayerInterface *lay); uint32_t ILayersAtOnce(uint32_t which); - - void IBuildLayerTexture(MTL::RenderCommandEncoder *encoder, uint32_t offsetFromRootLayer, plLayerInterface* layer); - void EncodeTransform(plLayerInterface* layer, UVOutDescriptor *transform); - std::vector> fPasses; + + void IBuildLayerTexture(MTL::RenderCommandEncoder *encoder, uint32_t offsetFromRootLayer, plLayerInterface *layer); + void EncodeTransform(plLayerInterface *layer, UVOutDescriptor *transform); + std::vector> fPasses; std::vector fFragmentShaderDescriptions; }; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 53aa2b437e..b05ee2fa5e 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -39,59 +39,50 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "HeadSpin.h" -#include +#include "plMetalPipeline.h" -#include #import -#include "plQuality.h" - -#include "plMetalPipeline.h" -#include "plMetalMaterialShaderRef.h" -#include "plMetalPlateManager.h" -#include "plMetalPipelineState.h" +#include +#include +#include "HeadSpin.h" +#include "hsGMatState.inl" #include "hsTimer.h" -#include "plPipeDebugFlags.h" -#include "plPipeResReq.h" - -#include "pnNetCommon/plNetApp.h" // for dbg logging -#include "pnMessage/plPipeResMakeMsg.h" +#include "pfCamera/plVirtualCamNeu.h" #include "plAvatar/plAvatarClothing.h" +#include "plDrawable/plAuxSpan.h" #include "plDrawable/plDrawableSpans.h" #include "plDrawable/plGBufferGroup.h" +#include "plGImage/plCubicEnvironmap.h" #include "plGImage/plMipmap.h" #include "plGLight/plLightInfo.h" +#include "plGLight/plShadowCaster.h" +#include "plGLight/plShadowSlave.h" +#include "plMessage/plDeviceRecreateMsg.h" +#include "plMetalFragmentShader.h" +#include "plMetalMaterialShaderRef.h" +#include "plMetalPipelineState.h" +#include "plMetalPlateManager.h" +#include "plMetalTextFont.h" +#include "plMetalVertexShader.h" +#include "plPipeDebugFlags.h" +#include "plPipeResReq.h" #include "plPipeline/plCubicRenderTarget.h" #include "plPipeline/plDebugText.h" #include "plPipeline/plDynamicEnvMap.h" +#include "plProfile.h" +#include "plQuality.h" #include "plScene/plRenderRequest.h" #include "plSurface/hsGMaterial.h" #include "plSurface/plLayer.h" -#include "pfCamera/plVirtualCamNeu.h" -#include "plMessage/plDeviceRecreateMsg.h" -#include "plgDispatch.h" -#include "plDrawable/plAuxSpan.h" #include "plSurface/plLayerShadowBase.h" -#include "plMetalTextFont.h" - -#include "plGImage/plMipmap.h" -#include "plGImage/plCubicEnvironmap.h" - -#include "plGLight/plShadowSlave.h" -#include "plGLight/plShadowCaster.h" - #include "plTweak.h" +#include "plgDispatch.h" +#include "pnMessage/plPipeResMakeMsg.h" +#include "pnNetCommon/plNetApp.h" // for dbg logging -#include "plMetalVertexShader.h" -#include "plMetalFragmentShader.h" - -#include "hsGMatState.inl" - -#include "plProfile.h" - -uint32_t fDbgSetupInitFlags; // HACK temp only +uint32_t fDbgSetupInitFlags; // HACK temp only plProfile_CreateCounter("Feed Triangles", "Draw", DrawFeedTriangles); plProfile_CreateCounter("Draw Prim Static", "Draw", DrawPrimStatic); @@ -129,17 +120,23 @@ plMetalEnumerate plMetalPipeline::enumerator; class plRenderTriListFunc : public plRenderPrimFunc { -protected: - plMetalDevice* fDevice; - int fBaseVertexIndex; - int fVStart; - int fVLength; - int fIStart; - int fNumTris; -public: + protected: + plMetalDevice* fDevice; + int fBaseVertexIndex; + int fVStart; + int fVLength; + int fIStart; + int fNumTris; + + public: plRenderTriListFunc(plMetalDevice* device, int baseVertexIndex, int vStart, int vLength, int iStart, int iNumTris) - : fDevice(device), fBaseVertexIndex(baseVertexIndex), fVStart(vStart), fVLength(vLength), fIStart(iStart), fNumTris(iNumTris) {} + : fDevice(device), + fBaseVertexIndex(baseVertexIndex), + fVStart(vStart), + fVLength(vLength), + fIStart(iStart), + fNumTris(iNumTris) {} bool RenderPrims() const override; }; @@ -149,48 +146,55 @@ bool plRenderTriListFunc::RenderPrims() const plProfile_IncCount(DrawFeedTriangles, fNumTris); plProfile_IncCount(DrawTriangles, fNumTris); plProfile_Inc(DrawPrimStatic); - + size_t uniformsSize = offsetof(VertexUniforms, uvTransforms) + sizeof(UVOutDescriptor) * fDevice->fPipeline->fCurrNumLayers; - fDevice->CurrentRenderCommandEncoder()->setVertexBytes(fDevice->fPipeline->fCurrentRenderPassUniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms); - + fDevice->CurrentRenderCommandEncoder()->setVertexBytes(fDevice->fPipeline->fCurrentRenderPassUniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms); + plMetalLights* lights = &fDevice->fPipeline->fLights; - size_t lightSize = offsetof(plMetalLights, lampSources) + (sizeof(plMetalShaderLightSource) * lights->count); - + size_t lightSize = offsetof(plMetalLights, lampSources) + (sizeof(plMetalShaderLightSource) * lights->count); + fDevice->CurrentRenderCommandEncoder()->setVertexBytes(lights, sizeof(plMetalLights), VertexShaderArgumentLights); fDevice->CurrentRenderCommandEncoder()->drawIndexedPrimitives(MTL::PrimitiveTypeTriangle, fNumTris, MTL::IndexTypeUInt16, fDevice->fCurrentIndexBuffer, (sizeof(uint16_t) * fIStart)); } - - -plMetalPipeline::plMetalPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) : pl3DPipeline(devMode), fRenderTargetRefList(), fMatRefList(), fCurrentRenderPassUniforms(nullptr), currentDrawableCallback(nullptr), fFragFunction(nullptr), fVShaderRefList(nullptr), fPShaderRefList(nullptr), fULutTextureRef(nullptr), fCurrRenderLayer() +plMetalPipeline::plMetalPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord* devMode) : pl3DPipeline(devMode), + fRenderTargetRefList(), + fMatRefList(), + fCurrentRenderPassUniforms(nullptr), + currentDrawableCallback(nullptr), + fFragFunction(nullptr), + fVShaderRefList(nullptr), + fPShaderRefList(nullptr), + fULutTextureRef(nullptr), + fCurrRenderLayer() { fTextureRefList = nullptr; fVtxBuffRefList = nullptr; fIdxBuffRefList = nullptr; fMatRefList = nullptr; fTextFontRefList = nullptr; - + fCurrLayerIdx = 0; fDevice.fPipeline = this; - + fMaxLayersAtOnce = 8; - + // Default our output format to 8 bit BGRA. Client may immediately change this to // the actual framebuffer format. SetFramebufferFormat(MTL::PixelFormatBGRA8Unorm); - + // Alloc half our simultaneous textures to piggybacks. // Won't hurt us unless we try to many things at once. fMaxPiggyBacks = fMaxLayersAtOnce >> 1; - + // Metal is always PS3 capable plQuality::SetCapability(plQuality::kPS_3); - + fDevice.SetMaxAnsiotropy(fInitialPipeParams.AnisotropicLevel); fDevice.SetMSAASampleCount(fInitialPipeParams.AntiAliasingAmount); - - fCurrentRenderPassUniforms = (VertexUniforms *) calloc(sizeof(VertexUniforms), sizeof(char)); - + + fCurrentRenderPassUniforms = (VertexUniforms*)calloc(sizeof(VertexUniforms), sizeof(char)); + // RenderTarget pools are shared for our shadow generation algorithm. // Different sizes for different resolutions. ICreateDeviceObjects(); @@ -206,13 +210,14 @@ plMetalPipeline::~plMetalPipeline() } } -void plMetalPipeline::ICreateDeviceObjects() { +void plMetalPipeline::ICreateDeviceObjects() +{ fPlateMgr = new plMetalPlateManager(this); } -bool plMetalPipeline::PreRender(plDrawable *drawable, std::vector &visList, plVisMgr *visMgr) +bool plMetalPipeline::PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) { - plDrawableSpans *ds = plDrawableSpans::ConvertNoRef(drawable); + plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable); if (!ds) { return false; } @@ -226,7 +231,7 @@ bool plMetalPipeline::PreRender(plDrawable *drawable, std::vector &visL return visList.size() > 0; } -bool plMetalPipeline::PrepForRender(plDrawable *drawable, std::vector &visList, plVisMgr *visMgr) +bool plMetalPipeline::PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) { plProfile_BeginTiming(PrepDrawable); @@ -248,7 +253,7 @@ bool plMetalPipeline::PrepForRender(plDrawable *drawable, std::vector & // do any last minute updates for its buffers, including // generating particle tri lists. ice->PrepForRender(this); - + // Any skinning necessary if (!ISoftwareVertexBlend(ice, visList)) { plProfile_EndTiming(PrepDrawable); @@ -260,21 +265,23 @@ bool plMetalPipeline::PrepForRender(plDrawable *drawable, std::vector & return true; } -plTextFont *plMetalPipeline::MakeTextFont(ST::string face, uint16_t size) { - plTextFont *font = new plMetalTextFont( this, &fDevice ); - font->Create( face, size ); - font->Link( &fTextFontRefList ); +plTextFont* plMetalPipeline::MakeTextFont(ST::string face, uint16_t size) +{ + plTextFont* font = new plMetalTextFont(this, &fDevice); + font->Create(face, size); + font->Link(&fTextFontRefList); return font; } -bool plMetalPipeline::OpenAccess(plAccessSpan &dst, plDrawableSpans *d, const plVertexSpan *span, bool readOnly) { +bool plMetalPipeline::OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) +{ //FIXME: Whats this? return false; } -bool plMetalPipeline::CloseAccess(plAccessSpan &acc) { return false; } +bool plMetalPipeline::CloseAccess(plAccessSpan& acc) { return false; } -void plMetalPipeline::PushRenderRequest(plRenderRequest *req) +void plMetalPipeline::PushRenderRequest(plRenderRequest* req) { // Save these, since we want to copy them to our current view hsMatrix44 l2w = fView.GetLocalToWorld(); @@ -315,12 +322,12 @@ void plMetalPipeline::PushRenderRequest(plRenderRequest *req) fState.Reset(); } -void plMetalPipeline::PopRenderRequest(plRenderRequest *req) +void plMetalPipeline::PopRenderRequest(plRenderRequest* req) { if (req->GetOverrideMat()) { PopOverrideMaterial(nil); } - + //new render target means we can't use the previous pipeline state //it won't be set yet on the new target //in theory we could have a stack of these so when we unwind we @@ -335,39 +342,40 @@ void plMetalPipeline::PopRenderRequest(plRenderRequest *req) fView.fXformResetFlags = fView.kResetProjection | fView.kResetCamera; } -plRenderTarget* plMetalPipeline::PopRenderTarget() { +plRenderTarget* plMetalPipeline::PopRenderTarget() +{ pl3DPipeline::PopRenderTarget(); fState.Reset(); } -void plMetalPipeline::ClearRenderTarget(plDrawable *d) +void plMetalPipeline::ClearRenderTarget(plDrawable* d) { plDrawableSpans* src = plDrawableSpans::ConvertNoRef(d); - if( !src ) + if (!src) { ClearRenderTarget(); return; } - + Draw(d); } -void plMetalPipeline::ClearRenderTarget(const hsColorRGBA *col, const float *depth) +void plMetalPipeline::ClearRenderTarget(const hsColorRGBA* col, const float* depth) { if (fView.fRenderState & (kRenderClearColor | kRenderClearDepth)) { hsColorRGBA clearColor = col ? *col : GetClearColor(); - float clearDepth = depth ? *depth : fView.GetClearDepth(); + float clearDepth = depth ? *depth : fView.GetClearDepth(); fDevice.Clear(fView.fRenderState & kRenderClearColor, {clearColor.r, clearColor.g, clearColor.b, clearColor.a}, fView.fRenderState & kRenderClearDepth, 1.0); fState.Reset(); } } -hsGDeviceRef *plMetalPipeline::MakeRenderTargetRef(plRenderTarget *owner) +hsGDeviceRef* plMetalPipeline::MakeRenderTargetRef(plRenderTarget* owner) { plMetalRenderTargetRef* ref = nullptr; - MTL::Texture *depthBuffer = nullptr; - plCubicRenderTarget *cubicRT; + MTL::Texture* depthBuffer = nullptr; + plCubicRenderTarget* cubicRT; // If we have Shader Model 3 and support non-POT textures, let's make reflections the pipe size if (plDynamicCamMap* camMap = plDynamicCamMap::ConvertNoRef(owner)) { @@ -384,14 +392,14 @@ hsGDeviceRef *plMetalPipeline::MakeRenderTargetRef(plRenderTarget *owner) // If we already have a rendertargetref, we just need it filled out with D3D resources. if (owner->GetDeviceRef()) ref = (plMetalRenderTargetRef*)owner->GetDeviceRef(); - + /// Create the render target now // Start with the depth surface. // Note that we only ever give a cubic rendertarget a single shared depth buffer, // since we only render one face at a time. If we were rendering part of face X, then part // of face Y, then more of face X, then they would all need their own depth buffers. if (owner->GetZDepth() && (owner->GetFlags() & (plRenderTarget::kIsTexture | plRenderTarget::kIsOffscreen))) { - MTL::TextureDescriptor *depthTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, + MTL::TextureDescriptor* depthTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, owner->GetWidth(), owner->GetHeight(), false); @@ -400,86 +408,84 @@ hsGDeviceRef *plMetalPipeline::MakeRenderTargetRef(plRenderTarget *owner) // this assumes the render target only needs to survive this render pass //FIXME: Do we need to promise the output survives the render pass? depthTextureDescriptor->setStorageMode(MTL::StorageModeMemoryless); - } else { + } else { depthTextureDescriptor->setStorageMode(MTL::StorageModePrivate); } depthTextureDescriptor->setUsage(MTL::TextureUsageRenderTarget); depthBuffer = fDevice.fMetalDevice->newTexture(depthTextureDescriptor); } - // See if it's a cubic render target. // Primary consumer here is the vertex/pixel shader water. - cubicRT = plCubicRenderTarget::ConvertNoRef( owner ); - if( cubicRT ) + cubicRT = plCubicRenderTarget::ConvertNoRef(owner); + if (cubicRT) { if (!ref) ref = new plMetalRenderTargetRef(); - - MTL::TextureDescriptor *textureDescriptor = MTL::TextureDescriptor::textureCubeDescriptor(MTL::PixelFormatBGRA8Unorm, owner->GetWidth(), false); + + MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::textureCubeDescriptor(MTL::PixelFormatBGRA8Unorm, owner->GetWidth(), false); textureDescriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead | MTL::TextureUsagePixelFormatView); textureDescriptor->setStorageMode(MTL::StorageModePrivate); - - plMetalDeviceRef *device = (plMetalDeviceRef *)owner->GetDeviceRef(); - MTL::Texture * texture = fDevice.fMetalDevice->newTexture(textureDescriptor); - + + plMetalDeviceRef* device = (plMetalDeviceRef*)owner->GetDeviceRef(); + MTL::Texture* texture = fDevice.fMetalDevice->newTexture(textureDescriptor); + /// Create a CUBIC texture - for( int i = 0; i < 6; i++ ) + for (int i = 0; i < 6; i++) { - plRenderTarget *face = cubicRT->GetFace( i ); - plMetalRenderTargetRef *fRef; + plRenderTarget* face = cubicRT->GetFace(i); + plMetalRenderTargetRef* fRef; - if( face->GetDeviceRef() != nil ) + if (face->GetDeviceRef() != nil) { - fRef = (plMetalRenderTargetRef *)face->GetDeviceRef(); - if( !fRef->IsLinked() ) - fRef->Link( &fRenderTargetRefList ); - } - else + fRef = (plMetalRenderTargetRef*)face->GetDeviceRef(); + if (!fRef->IsLinked()) + fRef->Link(&fRenderTargetRefList); + } else { fRef = new plMetalRenderTargetRef(); - + face->SetDeviceRef(fRef); - ( (plMetalRenderTargetRef *)face->GetDeviceRef())->Link( &fRenderTargetRefList ); + ((plMetalRenderTargetRef*)face->GetDeviceRef())->Link(&fRenderTargetRefList); // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) - hsRefCnt_SafeUnRef( face->GetDeviceRef() ); + hsRefCnt_SafeUnRef(face->GetDeviceRef()); } - + //in since the root texture has changed reload all the face textures static const uint kFaceMapping[] = { - 1, // kLeftFace - 0, // kRightFace - 4, // kFrontFace - 5, // kBackFace - 2, // kTopFace - 3 // kBottomFace + 1, // kLeftFace + 0, // kRightFace + 4, // kFrontFace + 5, // kBackFace + 2, // kTopFace + 3 // kBottomFace }; - - if(fRef->fTexture) { + + if (fRef->fTexture) { fRef->fTexture->release(); fRef->fTexture = nullptr; } - - if(fRef->fDepthBuffer) { + + if (fRef->fDepthBuffer) { fRef->fDepthBuffer->release(); fRef->fDepthBuffer = nullptr; } - + fRef->fTexture = texture->newTextureView(MTL::PixelFormatBGRA8Unorm, MTL::TextureType2D, NS::Range::Make(0, 1), NS::Range::Make(kFaceMapping[i], 1)); //in since the depth buffer is shared each render target gets their own retain fRef->fDepthBuffer = depthBuffer->retain(); fRef->SetDirty(false); } - + //if the ref already has an old texture, release it - if(ref->fTexture) + if (ref->fTexture) ref->fTexture->release(); - if(ref->fDepthBuffer) + if (ref->fDepthBuffer) ref->fDepthBuffer->release(); ref->fTexture = texture; ref->fDepthBuffer = depthBuffer; ref->fOwner = owner; - + // Keep it in a linked list for ready destruction. if (owner->GetDeviceRef() != ref) { owner->SetDeviceRef(ref); @@ -492,33 +498,32 @@ hsGDeviceRef *plMetalPipeline::MakeRenderTargetRef(plRenderTarget *owner) ref->Link(&fRenderTargetRefList); } ref->SetDirty(false); - + return ref; - } - else if (owner->GetFlags() & plRenderTarget::kIsTexture) { + } else if (owner->GetFlags() & plRenderTarget::kIsTexture) { if (!ref) ref = new plMetalRenderTargetRef(); - - MTL::TextureDescriptor *textureDescriptor = MTL::TextureDescriptor::alloc()->init(); + + MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::alloc()->init(); textureDescriptor->setWidth(owner->GetWidth()); textureDescriptor->setHeight(owner->GetHeight()); textureDescriptor->setPixelFormat(MTL::PixelFormatBGRA8Unorm); textureDescriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite); textureDescriptor->setStorageMode(MTL::StorageModePrivate); - - plMetalDeviceRef *device = (plMetalDeviceRef *)owner->GetDeviceRef(); - MTL::Texture * texture = fDevice.fMetalDevice->newTexture(textureDescriptor); + + plMetalDeviceRef* device = (plMetalDeviceRef*)owner->GetDeviceRef(); + MTL::Texture* texture = fDevice.fMetalDevice->newTexture(textureDescriptor); textureDescriptor->release(); - + //if the ref already has an old texture, release it - if(ref->fTexture) + if (ref->fTexture) ref->fTexture->release(); - if(ref->fDepthBuffer) + if (ref->fDepthBuffer) ref->fDepthBuffer->release(); ref->fTexture = texture; ref->fDepthBuffer = depthBuffer; ref->fOwner = owner; - + // Keep it in a linked list for ready destruction. if (owner->GetDeviceRef() != ref) { owner->SetDeviceRef(ref); @@ -530,53 +535,54 @@ hsGDeviceRef *plMetalPipeline::MakeRenderTargetRef(plRenderTarget *owner) if (ref != nullptr && !ref->IsLinked()) ref->Link(&fRenderTargetRefList); } - + return ref; } - + // Not a texture either, must be a plain offscreen. // Offscreen isn't currently used for anything. - else if (owner->GetFlags() & plRenderTarget::kIsOffscreen) { + else if (owner->GetFlags() & plRenderTarget::kIsOffscreen) + { /// Create a blank surface - - if (!ref) - ref = new plMetalRenderTargetRef(); - - MTL::TextureDescriptor *textureDescriptor = MTL::TextureDescriptor::alloc()->init(); - textureDescriptor->setWidth(owner->GetWidth()); - textureDescriptor->setHeight(owner->GetHeight()); - textureDescriptor->setPixelFormat(MTL::PixelFormatBGRA8Unorm); - textureDescriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead); - textureDescriptor->setStorageMode(MTL::StorageModeManaged); - - plMetalDeviceRef *device = (plMetalDeviceRef *)owner->GetDeviceRef(); - MTL::Texture * texture = fDevice.fMetalDevice->newTexture(textureDescriptor); - textureDescriptor->release(); - - //if the ref already has an old texture, release it - if(ref->fTexture) - ref->fTexture->release(); - if(ref->fDepthBuffer) - ref->fDepthBuffer->release(); - ref->fTexture = texture; - ref->fDepthBuffer = depthBuffer; - ref->fOwner = owner; - - // Keep it in a linked list for ready destruction. - if (owner->GetDeviceRef() != ref) { - owner->SetDeviceRef(ref); - // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) - hsRefCnt_SafeUnRef(ref); - if (ref != nullptr && !ref->IsLinked()) - ref->Link(&fRenderTargetRefList); - } else { - if (ref != nullptr && !ref->IsLinked()) - ref->Link(&fRenderTargetRefList); - } - - return ref; + + if (!ref) + ref = new plMetalRenderTargetRef(); + + MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::alloc()->init(); + textureDescriptor->setWidth(owner->GetWidth()); + textureDescriptor->setHeight(owner->GetHeight()); + textureDescriptor->setPixelFormat(MTL::PixelFormatBGRA8Unorm); + textureDescriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead); + textureDescriptor->setStorageMode(MTL::StorageModeManaged); + + plMetalDeviceRef* device = (plMetalDeviceRef*)owner->GetDeviceRef(); + MTL::Texture* texture = fDevice.fMetalDevice->newTexture(textureDescriptor); + textureDescriptor->release(); + + //if the ref already has an old texture, release it + if (ref->fTexture) + ref->fTexture->release(); + if (ref->fDepthBuffer) + ref->fDepthBuffer->release(); + ref->fTexture = texture; + ref->fDepthBuffer = depthBuffer; + ref->fOwner = owner; + + // Keep it in a linked list for ready destruction. + if (owner->GetDeviceRef() != ref) { + owner->SetDeviceRef(ref); + // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) + hsRefCnt_SafeUnRef(ref); + if (ref != nullptr && !ref->IsLinked()) + ref->Link(&fRenderTargetRefList); + } else { + if (ref != nullptr && !ref->IsLinked()) + ref->Link(&fRenderTargetRefList); + } + + return ref; } - + // Keep it in a linked list for ready destruction. if (owner->GetDeviceRef() != ref) { owner->SetDeviceRef(ref); @@ -603,9 +609,9 @@ bool plMetalPipeline::BeginRender() fCurrentPool = NS::AutoreleasePool::alloc()->init(); // offset transform RefreshScreenMatrices(); - + fState.Reset(); - + // offset transform RefreshScreenMatrices(); @@ -619,15 +625,15 @@ bool plMetalPipeline::BeginRender() // Render any shadow maps that have been submitted for this frame. IPreprocessShadows(); IPreprocessAvatarTextures(); - - CA::MetalDrawable *drawable = currentDrawableCallback(fDevice.fMetalDevice); - if(!drawable) { + + CA::MetalDrawable* drawable = currentDrawableCallback(fDevice.fMetalDevice); + if (!drawable) { fCurrentPool->release(); return true; } fDevice.CreateNewCommandBuffer(drawable); drawable->release(); - + /// If we have a renderTarget active, use its viewport //FIXME: New drawables should inherit existing viewport //fDevice.SetViewport(); @@ -645,13 +651,13 @@ bool plMetalPipeline::EndRender() { bool retVal = false; fState.Reset(); - + if (--fInSceneDepth == 0) { fDevice.SubmitCommandBuffer(); - + IClearShadowSlaves(); } - + // Do this last, after we've drawn everything // Just letting go of things we're done with for the frame. hsRefCnt_SafeUnRef(fCurrMaterial); @@ -668,7 +674,8 @@ bool plMetalPipeline::EndRender() return retVal; } -void plMetalPipeline::RenderScreenElements() { +void plMetalPipeline::RenderScreenElements() +{ bool reset = false; if (fView.HasCullProxy()) @@ -676,7 +683,6 @@ void plMetalPipeline::RenderScreenElements() { Draw(fView.GetCullProxy()); } - hsGMatState tHack = PushMaterialOverride(hsGMatState::kMisc, hsGMatState::kMiscWireFrame, false); hsGMatState ambHack = PushMaterialOverride(hsGMatState::kShade, hsGMatState::kShadeWhite, true); @@ -704,7 +710,7 @@ void plMetalPipeline::RenderScreenElements() { plProfile_BeginTiming(Reset); if (reset) { - fView.fXformResetFlags = fView.kResetAll; // Text destroys view transforms + fView.fXformResetFlags = fView.kResetAll; // Text destroys view transforms } plProfile_EndTiming(Reset); } @@ -718,7 +724,7 @@ void plMetalPipeline::Resize(uint32_t width, uint32_t height) This function is cheaper than resetting the entire display device though. */ - hsMatrix44 w2c, c2w, proj; + hsMatrix44 w2c, c2w, proj; // Store some states that we *want* to restore back... plViewTransform resetTransform = GetViewTransform(); @@ -726,30 +732,29 @@ void plMetalPipeline::Resize(uint32_t width, uint32_t height) // Destroy old IReleaseDeviceObjects(); IReleaseDynDeviceObjects(); - + // Reset width and height - if( width != 0 && height != 0 ) + if (width != 0 && height != 0) { // Width and height of zero mean just recreate fOrigWidth = width; fOrigHeight = height; IGetViewTransform().SetScreenSize((uint16_t)(fOrigWidth), (uint16_t)(fOrigHeight)); resetTransform.SetScreenSize((uint16_t)(fOrigWidth), (uint16_t)(fOrigHeight)); - } - else + } else { // Just for debug - hsStatusMessage( "Recreating the pipeline...\n" ); + hsStatusMessage("Recreating the pipeline...\n"); } - + ICreateDeviceObjects(); // Restore states SetViewTransform(resetTransform); IProjectionMatrixToDevice(); - + plVirtualCam1::Refresh(); - + ICreateDynDeviceObjects(); /// Broadcast a message letting everyone know that we were recreated and that @@ -758,27 +763,26 @@ void plMetalPipeline::Resize(uint32_t width, uint32_t height) plgDispatch::MsgSend(clean); } - void plMetalPipeline::IReleaseDeviceObjects() { IReleaseDynDeviceObjects(); - + delete fPlateMgr; fPlateMgr = nullptr; } void plMetalPipeline::LoadResources() { - hsStatusMessageF("Begin Device Reload t=%f",hsTimer::GetSeconds()); + hsStatusMessageF("Begin Device Reload t=%f", hsTimer::GetSeconds()); plNetClientApp::StaticDebugMsg("Begin Device Reload"); - - if(fFragFunction == nil) { + + if (fFragFunction == nil) { FindFragFunction(); } if (plMetalPlateManager* pm = static_cast(fPlateMgr)) pm->IReleaseGeometry(); - + IReleaseDynamicBuffers(); IReleaseAvRTPool(); @@ -806,7 +810,7 @@ void plMetalPipeline::LoadResources() plProfile_IncCount(PipeReload, 1); - hsStatusMessageF("End Device Reload t=%f",hsTimer::GetSeconds()); + hsStatusMessageF("End Device Reload t=%f", hsTimer::GetSeconds()); plNetClientApp::StaticDebugMsg("End Device Reload"); } @@ -819,21 +823,21 @@ bool plMetalPipeline::SetGamma(float eR, float eG, float eB) tabR[0] = tabG[0] = tabB[0] = 0L; plConst(float) kMinE(0.1f); - if( eR > kMinE ) + if (eR > kMinE) eR = 1.f / eR; else eR = 1.f / kMinE; - if( eG > kMinE ) + if (eG > kMinE) eG = 1.f / eG; else eG = 1.f / kMinE; - if( eB > kMinE ) + if (eB > kMinE) eB = 1.f / eB; else eB = 1.f / kMinE; int i; - for( i = 1; i < 256; i++ ) + for (i = 1; i < 256; i++) { float orig = float(i) / 255.f; @@ -856,14 +860,14 @@ bool plMetalPipeline::SetGamma(float eR, float eG, float eB) return true; } -bool plMetalPipeline::SetGamma(const uint16_t *const tabR, const uint16_t *const tabG, const uint16_t *const tabB) +bool plMetalPipeline::SetGamma(const uint16_t* const tabR, const uint16_t* const tabG, const uint16_t* const tabB) { //allocate a new buffer every time so we don't cause problems with a running render pass - if(fDevice.fGammaLUTTexture) { + if (fDevice.fGammaLUTTexture) { fDevice.fGammaLUTTexture->release(); fDevice.fGammaLUTTexture = nullptr; } - + /* Plasma has multiple types of gamma corrections it can do - and the engine reserves the right to create any color correct LUT. Ugh. Load the LUT into a texture as 8 bit @@ -875,96 +879,96 @@ bool plMetalPipeline::SetGamma(const uint16_t *const tabR, const uint16_t *const texDescriptor->setWidth(256); texDescriptor->setPixelFormat(MTL::PixelFormatR16Uint); texDescriptor->setArrayLength(3); - + fDevice.fGammaLUTTexture = fDevice.fMetalDevice->newTexture(texDescriptor); - + fDevice.fGammaLUTTexture->replaceRegion(MTL::Region(0, 256), 0, 0, tabR, 256 * sizeof(uint16_t), 0); fDevice.fGammaLUTTexture->replaceRegion(MTL::Region(0, 256), 0, 1, tabG, 256 * sizeof(uint16_t), 0); fDevice.fGammaLUTTexture->replaceRegion(MTL::Region(0, 256), 0, 2, tabB, 256 * sizeof(uint16_t), 0); - + return true; } -bool plMetalPipeline::SetGamma10(const uint16_t *const tabR, const uint16_t *const tabG, const uint16_t *const tabB) +bool plMetalPipeline::SetGamma10(const uint16_t* const tabR, const uint16_t* const tabG, const uint16_t* const tabB) { //allocate a new buffer every time so we don't cause problems with a running render pass - if(fDevice.fGammaLUTTexture) { + if (fDevice.fGammaLUTTexture) { fDevice.fGammaLUTTexture->release(); fDevice.fGammaLUTTexture = nullptr; } - + /* Loads in a real 10 bit color LUT for fancy displays. This LUT contains way more data - but the shader doesn't care. The shader does an x lookup by normalized co-ordinate - not value. So the width of the texture can vary. */ - + MTL::TextureDescriptor* texDescriptor = MTL::TextureDescriptor::alloc()->init()->autorelease(); texDescriptor->setTextureType(MTL::TextureType1DArray); texDescriptor->setWidth(1024); texDescriptor->setPixelFormat(MTL::PixelFormatR16Uint); texDescriptor->setArrayLength(3); - + fDevice.fGammaLUTTexture = fDevice.fMetalDevice->newTexture(texDescriptor); - + fDevice.fGammaLUTTexture->replaceRegion(MTL::Region(0, 1024), 0, 0, tabR, 1024 * sizeof(uint16_t), 0); fDevice.fGammaLUTTexture->replaceRegion(MTL::Region(0, 1024), 0, 1, tabG, 1024 * sizeof(uint16_t), 0); fDevice.fGammaLUTTexture->replaceRegion(MTL::Region(0, 1024), 0, 2, tabB, 1024 * sizeof(uint16_t), 0); - + return true; } -bool plMetalPipeline::CaptureScreen(plMipmap *dest, bool flipVertical, uint16_t desiredWidth, uint16_t desiredHeight) +bool plMetalPipeline::CaptureScreen(plMipmap* dest, bool flipVertical, uint16_t desiredWidth, uint16_t desiredHeight) { //FIXME: Screen capture //FIXME: Double fix me - wasn't this working? return false; } -plMipmap *plMetalPipeline::ExtractMipMap(plRenderTarget *targ) +plMipmap* plMetalPipeline::ExtractMipMap(plRenderTarget* targ) { - if( plCubicRenderTarget::ConvertNoRef(targ) ) + if (plCubicRenderTarget::ConvertNoRef(targ)) return nullptr; - if( targ->GetPixelSize() != 32 ) + if (targ->GetPixelSize() != 32) { hsAssert(false, "Only RGBA8888 currently implemented"); return nullptr; } - + plMetalRenderTargetRef* ref = (plMetalRenderTargetRef*)targ->GetDeviceRef(); - if( !ref ) + if (!ref) return nullptr; - + const int width = targ->GetWidth(); const int height = targ->GetHeight(); plMipmap* mipMap = new plMipmap(width, height, plMipmap::kARGB32Config, 1); - uint8_t* ptr = (uint8_t*)(ref->fTexture->buffer()->contents()); + uint8_t* ptr = (uint8_t*)(ref->fTexture->buffer()->contents()); const NS::UInteger pitch = ref->fTexture->width() * 4; - + ref->fTexture->getBytes(mipMap->GetAddr32(0, 0), pitch, MTL::Region(0, 0, width, height), 0); const uint32_t blackOpaque = 0xff000000; - int y; - for( y = 0; y < height; y++ ) + int y; + for (y = 0; y < height; y++) { uint32_t* destPtr = mipMap->GetAddr32(0, y); uint32_t* srcPtr = (uint32_t*)destPtr; - int x; - for( x = 0; x < width; x++ ) + int x; + for (x = 0; x < width; x++) { destPtr[x] = srcPtr[x] | blackOpaque; } ptr += pitch; } - + return mipMap; } -void plMetalPipeline::GetSupportedDisplayModes(std::vector *res, int ColorDepth) +void plMetalPipeline::GetSupportedDisplayModes(std::vector* res, int ColorDepth) { /* There are decisions to make here. @@ -977,14 +981,14 @@ void plMetalPipeline::GetSupportedDisplayModes(std::vector *res, Ideally we should support some sort of scaling/semi dynamic renderbuffer resolution thing. But don't mess with the window servers framebuffer size. macOS has accelerated resolution scaling like consoles do. Use that. */ - + std::vector supported; - plDisplayMode mode; + plDisplayMode mode; mode.Width = 800; mode.Height = 600; mode.ColorDepth = 32; supported.push_back(mode); - + *res = supported; } @@ -1014,31 +1018,30 @@ void plMetalPipeline::ResetDisplayDevice(int Width, int Height, int ColorDepth, { //FIXME: Whats this? //Seems like an entry point for passing in display settings. - + fDevice.SetMaxAnsiotropy(MaxAnisotropicSamples); } -void plMetalPipeline::RenderSpans(plDrawableSpans *ice, const std::vector &visList) +void plMetalPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& visList) { plProfile_BeginTiming(RenderSpan); - hsMatrix44 lastL2W; - size_t i, j; - hsGMaterial* material; + hsMatrix44 lastL2W; + size_t i, j; + hsGMaterial* material; const std::vector& spans = ice->GetSpanArray(); //plProfile_IncCount(EmptyList, !visList.GetCount()); /// Set this (*before* we do our TestVisibleWorld stuff...) lastL2W.Reset(); - ISetLocalToWorld(lastL2W, lastL2W); // This is necessary; otherwise, we have to test for - // the first transform set, since this'll be identity - // but the actual device transform won't be (unless - // we do this) - + ISetLocalToWorld(lastL2W, lastL2W); // This is necessary; otherwise, we have to test for + // the first transform set, since this'll be identity + // but the actual device transform won't be (unless + // we do this) /// Loop through our spans, combining them when possible - for (i = 0; i < visList.size(); ) { + for (i = 0; i < visList.size();) { if (GetOverrideMaterial() != nullptr) { material = GetOverrideMaterial(); } else { @@ -1079,8 +1082,8 @@ void plMetalPipeline::RenderSpans(plDrawableSpans *ice, const std::vectorIsLinked()) { mRef->Link(&fMatRefList); } - - hsGDeviceRef* vb = ice->GetVertexRef( tempIce.fGroupIdx, tempIce.fVBufferIdx ); + + hsGDeviceRef* vb = ice->GetVertexRef(tempIce.fGroupIdx, tempIce.fVBufferIdx); plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)vb; // What do we change? @@ -1101,12 +1104,12 @@ void plMetalPipeline::RenderSpans(plDrawableSpans *ice, const std::vectorGetIndexRef( tempIce.fGroupIdx, tempIce.fIBufferIdx ), - material, - tempIce.fVStartIdx, tempIce.fVLength, // These are used as our accumulated range - tempIce.fIPackedIdx, tempIce.fILength ); + IRenderBufferSpan(tempIce, + vb, + ice->GetIndexRef(tempIce.fGroupIdx, tempIce.fIBufferIdx), + material, + tempIce.fVStartIdx, tempIce.fVLength, // These are used as our accumulated range + tempIce.fIPackedIdx, tempIce.fILength); } // Restart our search... @@ -1121,24 +1124,24 @@ void plMetalPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& { if (span.fNumMatrices) { if (span.fNumMatrices <= 2) { - ISetLocalToWorld( span.fLocalToWorld, span.fWorldToLocal ); + ISetLocalToWorld(span.fLocalToWorld, span.fWorldToLocal); lastL2W = span.fLocalToWorld; } else { lastL2W.Reset(); - ISetLocalToWorld( lastL2W, lastL2W ); + ISetLocalToWorld(lastL2W, lastL2W); fView.fLocalToWorldLeftHanded = span.fLocalToWorld.GetParity(); } } else if (lastL2W != span.fLocalToWorld) { - ISetLocalToWorld( span.fLocalToWorld, span.fWorldToLocal ); + ISetLocalToWorld(span.fLocalToWorld, span.fWorldToLocal); lastL2W = span.fLocalToWorld; } else { fView.fLocalToWorldLeftHanded = lastL2W.GetParity(); } - if( span.fNumMatrices == 2 ) + if (span.fNumMatrices == 2) { matrix_float4x4 mat; - hsMatrix2SIMD(drawable->GetPaletteMatrix(span.fBaseMatrix+1), &mat); + hsMatrix2SIMD(drawable->GetPaletteMatrix(span.fBaseMatrix + 1), &mat); fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&mat, sizeof(matrix_float4x4), VertexShaderArgumentBlendMatrix1); } @@ -1149,25 +1152,25 @@ void plMetalPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& } void plMetalPipeline::IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, - hsGDeviceRef* ib, hsGMaterial* material, - uint32_t vStart, uint32_t vLength, - uint32_t iStart, uint32_t iLength) + hsGDeviceRef* ib, hsGMaterial* material, + uint32_t vStart, uint32_t vLength, + uint32_t iStart, uint32_t iLength) { - if(iLength == 0) { + if (iLength == 0) { return; } - + plProfile_BeginTiming(RenderBuff); - plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)vb; - plMetalIndexBufferRef* iRef = (plMetalIndexBufferRef*)ib; + plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)vb; + plMetalIndexBufferRef* iRef = (plMetalIndexBufferRef*)ib; plMetalMaterialShaderRef* mRef = (plMetalMaterialShaderRef*)material->GetDeviceRef(); mRef->CheckMateralRef(); if (!vRef || !vRef->GetBuffer() || !iRef->GetBuffer()) { plProfile_EndTiming(RenderBuff); - hsAssert( false, ST::format("Trying to render a nil buffer pair! (Mat: {})", material->GetKeyName()).c_str() ); + hsAssert(false, ST::format("Trying to render a nil buffer pair! (Mat: {})", material->GetKeyName()).c_str()); return; } @@ -1186,16 +1189,16 @@ void plMetalPipeline::IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, } } #endif - + // Turn on this spans lights and turn off the rest. ISelectLights(&span, mRef); - + #ifdef HS_DEBUGGING fDevice.CurrentRenderCommandEncoder()->pushDebugGroup(NS::String::string(material->GetKeyName().c_str(), NS::UTF8StringEncoding)); #endif - + /* Vertex Buffer stuff */ - if(!vRef->GetBuffer()) { + if (!vRef->GetBuffer()) { return; } if (fState.fCurrentVertexBuffer != vRef->GetBuffer()) { @@ -1203,26 +1206,25 @@ void plMetalPipeline::IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, fState.fCurrentVertexBuffer = vRef->GetBuffer(); } fDevice.fCurrentIndexBuffer = iRef->GetBuffer(); - + IPushPiggyBacks(material); hsRefCnt_SafeAssign(fCurrMaterial, material); uint32_t pass; for (pass = 0; pass < mRef->GetNumPasses(); pass++) { - - if ( IHandleMaterialPass(material, pass, &span, vRef) ) { + if (IHandleMaterialPass(material, pass, &span, vRef)) { render.RenderPrims(); } - + //Projection wants to do it's own lighting, push the current lighting state //so we can keep the same light calculations on the next pass PushCurrentLightSources(); - + plProfile_BeginTiming(SelectProj); - ISelectLights( &span, mRef, true ); + ISelectLights(&span, mRef, true); plProfile_EndTiming(SelectProj); - + // Take care of projections that get applied to each pass. - if( fProjEach.size() && !(fView.fRenderState & kRenderNoProjection) ) + if (fProjEach.size() && !(fView.fRenderState & kRenderNoProjection)) { #ifdef HS_DEBUGGING fDevice.CurrentRenderCommandEncoder()->pushDebugGroup(NS::String::string("Render projections", NS::UTF8StringEncoding)); @@ -1234,49 +1236,47 @@ void plMetalPipeline::IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, } //Revert the light state back to what we had before projections PopCurrentLightSources(); - + if (IsDebugFlagSet(plPipeDbg::kFlagNoUpperLayers)) pass = mRef->GetNumPasses(); } - + IPopPiggyBacks(); - + // Render any aux spans associated. - if( span.GetNumAuxSpans() ) { + if (span.GetNumAuxSpans()) { IRenderAuxSpans(span); - + //aux spans will change the current vertex buffer, put ours back fDevice.CurrentRenderCommandEncoder()->setVertexBuffer(vRef->GetBuffer(), 0, 0); fState.fCurrentVertexBuffer = vRef->GetBuffer(); } - - // Only render projections and shadows if we successfully rendered the span. // j == -1 means we aborted render. - if( pass >= 0 ) + if (pass >= 0) { //if we had to render aux spans, we probably changed the vertex and index buffer //reset those fState.fCurrentVertexBuffer = vRef->GetBuffer(); fDevice.fCurrentIndexBuffer = iRef->GetBuffer(); - + // Projections that get applied to the frame buffer (after all passes). - if( fProjAll.size() && !(fView.fRenderState & kRenderNoProjection) ) { + if (fProjAll.size() && !(fView.fRenderState & kRenderNoProjection)) { fDevice.CurrentRenderCommandEncoder()->pushDebugGroup(NS::MakeConstantString("Render All Projections")); IRenderProjections(render, vRef); fDevice.CurrentRenderCommandEncoder()->popDebugGroup(); } // Handle render of shadows onto geometry. - if( fShadows.size() ) { + if (fShadows.size()) { IRenderShadowsOntoSpan(render, &span, material, vRef); } } - - if ( span.GetNumAuxSpans() || (pass >= 0 && fShadows.size()) ) { + + if (span.GetNumAuxSpans() || (pass >= 0 && fShadows.size())) { } - + #ifdef HS_DEBUGGING fDevice.CurrentRenderCommandEncoder()->popDebugGroup(); #endif @@ -1307,9 +1307,9 @@ void plMetalPipeline::IRenderProjection(const plRenderPrimFunc& render, plLightI plLayerInterface* proj = li->GetProjection(); CheckTextureRef(proj); plMetalTextureRef* tex = (plMetalTextureRef*)proj->GetTexture()->GetDeviceRef(); - + IScaleLight(0, true); - + fCurrentRenderPassUniforms->ambientSrc = 1.0; fCurrentRenderPassUniforms->diffuseSrc = 1.0; fCurrentRenderPassUniforms->emissiveSrc = 1.0; @@ -1320,31 +1320,30 @@ void plMetalPipeline::IRenderProjection(const plRenderPrimFunc& render, plLightI fCurrentRenderPassUniforms->specularCol = {0.0, 0.0, 0.0}; fCurrentRenderPassUniforms->fogColor = {0.0, 0.0, 0.0}; fCurrentRenderPassUniforms->diffuseCol = {1.0, 1.0, 1.0, 1.0}; - - + matrix_float4x4 tXfm; hsMatrix2SIMD(proj->GetTransform(), &tXfm); fCurrentRenderPassUniforms->uvTransforms[0].transform = tXfm; fCurrentRenderPassUniforms->uvTransforms[0].UVWSrc = proj->GetUVWSrc(); - + fCurrNumLayers = 1; // We should have put ZNoZWrite on during export, but we didn't. IHandleZMode(hsGMatState::kZNoZWrite); - + //This is a bit weird - in since this isn't a material we need to build a query for the right Metal program ourselves plMetalFragmentShaderDescription description; memset(&description, 0, sizeof(description)); description.numLayers = fCurrNumLayers = 1; - + description.Populate(proj, 0); //DX sets the color invert when the final color should be inverted. Not sure why! - if( proj->GetBlendFlags() & hsGMatState::kBlendInvertFinalColor ) { + if (proj->GetBlendFlags() & hsGMatState::kBlendInvertFinalColor) { description.blendModes[0] |= hsGMatState::kBlendInvertColor; } - - plMetalMaterialPassPipelineState materialShaderState(&fDevice, vRef, description); + + plMetalMaterialPassPipelineState materialShaderState(&fDevice, vRef, description); plMetalDevice::plMetalLinkedPipeline* linkedPipeline = materialShaderState.GetRenderPipelineState(); - + fState.fCurrentPipelineState = linkedPipeline->pipelineState; fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(linkedPipeline->pipelineState); fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(tex->fTexture, 0); @@ -1371,11 +1370,11 @@ void plMetalPipeline::IRenderProjectionEach(const plRenderPrimFunc& render, hsGM // For each projector: int k; - for( k = 0; k < fProjEach.size(); k++ ) + for (k = 0; k < fProjEach.size(); k++) { // Push it's projected texture as a piggyback. - plLightInfo* li = fProjEach[k]; - plMetalMaterialShaderRef *mRef = (plMetalMaterialShaderRef *)material->GetDeviceRef(); + plLightInfo* li = fProjEach[k]; + plMetalMaterialShaderRef* mRef = (plMetalMaterialShaderRef*)material->GetDeviceRef(); plLayerInterface* proj = li->GetProjection(); hsAssert(proj, "A projector with no texture to project?"); @@ -1387,8 +1386,8 @@ void plMetalPipeline::IRenderProjectionEach(const plRenderPrimFunc& render, hsGM AppendLayerInterface(&layLightBase, false); - IHandleMaterialPass( material, iPass, &span, vRef, false ); - + IHandleMaterialPass(material, iPass, &span, vRef, false); + IScaleLight(0, true); // Do the render with projection. @@ -1398,12 +1397,9 @@ void plMetalPipeline::IRenderProjectionEach(const plRenderPrimFunc& render, hsGM // Pop it's projected texture off piggyback IPopProjPiggyBacks(); - } - } - // ICheckAuxBuffers /////////////////////////////////////////////////////////////////////// // The AuxBuffers are associated with drawables for things to be drawn right after that // drawable's contents. In particular, see the plDynaDecal, which includes things like @@ -1415,21 +1411,21 @@ bool plMetalPipeline::ICheckAuxBuffers(const plAuxSpan* span) plGBufferGroup* group = span->fGroup; plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)group->GetVertexBufferRef(span->fVBufferIdx); - if( !vRef ) + if (!vRef) return true; plMetalIndexBufferRef* iRef = (plMetalIndexBufferRef*)group->GetIndexBufferRef(span->fIBufferIdx); - if( !iRef ) + if (!iRef) return true; // If our vertex buffer ref is volatile and the timestamp is off // then it needs to be refilled - if( vRef->Expired(fVtxRefTime) ) + if (vRef->Expired(fVtxRefTime)) { IRefreshDynVertices(group, vRef); } - return false; // No error + return false; // No error } // IRenderAuxSpans //////////////////////////////////////////////////////////////////////////// @@ -1443,11 +1439,10 @@ void plMetalPipeline::IRenderAuxSpans(const plSpan& span) ISetLocalToWorld(hsMatrix44::IdentityMatrix(), hsMatrix44::IdentityMatrix()); int i; - for( i = 0; i < span.GetNumAuxSpans(); i++ ) + for (i = 0; i < span.GetNumAuxSpans(); i++) IRenderAuxSpan(span, span.GetAuxSpan(i)); ISetLocalToWorld(span.fLocalToWorld, span.fWorldToLocal); - } // IRenderAuxSpan ////////////////////////////////////////////////////////// @@ -1467,93 +1462,90 @@ void plMetalPipeline::IRenderAuxSpan(const plSpan& span, const plAuxSpan* aux) // Set to render from the aux spans buffers. plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)aux->fGroup->GetVertexBufferRef(aux->fVBufferIdx); - if( !vRef ) + if (!vRef) return; plMetalIndexBufferRef* iRef = (plMetalIndexBufferRef*)aux->fGroup->GetIndexBufferRef(aux->fIBufferIdx); - if( !iRef ) + if (!iRef) return; - // Now just loop through the aux material, rendering in as many passes as it takes. - hsGMaterial* material = aux->fMaterial; + hsGMaterial* material = aux->fMaterial; plMetalMaterialShaderRef* mRef = (plMetalMaterialShaderRef*)material->GetDeviceRef(); - + if (mRef == nullptr) { mRef = new plMetalMaterialShaderRef(material, this); material->SetDeviceRef(mRef); } - + /* Vertex Buffer stuff */ - if(!vRef->GetBuffer()) { + if (!vRef->GetBuffer()) { return; } fDevice.CurrentRenderCommandEncoder()->setVertexBuffer(vRef->GetBuffer(), 0, 0); fState.fCurrentVertexBuffer = vRef->GetBuffer(); fDevice.fCurrentIndexBuffer = iRef->GetBuffer(); - + plRenderTriListFunc render(&fDevice, 0, aux->fVStartIdx, aux->fVLength, aux->fIStartIdx, aux->fILength); - + for (int32_t pass = 0; pass < mRef->GetNumPasses(); pass++) { IHandleMaterialPass(material, pass, &span, vRef); - if( aux->fFlags & plAuxSpan::kOverrideLiteModel ) + if (aux->fFlags & plAuxSpan::kOverrideLiteModel) { fCurrentRenderPassUniforms->ambientCol = {1.0f, 1.0f, 1.0f}; - + fCurrentRenderPassUniforms->diffuseSrc = 1.0; fCurrentRenderPassUniforms->ambientSrc = 1.0; fCurrentRenderPassUniforms->emissiveSrc = 0.0; fCurrentRenderPassUniforms->specularSrc = 1.0; } - + render.RenderPrims(); } } -bool plMetalPipeline::IHandleMaterialPass(hsGMaterial *material, uint32_t pass, const plSpan *currSpan, const plMetalVertexBufferRef* vRef, const bool allowShaders) +bool plMetalPipeline::IHandleMaterialPass(hsGMaterial* material, uint32_t pass, const plSpan* currSpan, const plMetalVertexBufferRef* vRef, const bool allowShaders) { plMetalMaterialShaderRef* mRef = (plMetalMaterialShaderRef*)material->GetDeviceRef(); - - fCurrLayerIdx = mRef->GetPassIndex(pass); - plLayerInterface *lay = material->GetLayer(mRef->GetPassIndex(pass)); + fCurrLayerIdx = mRef->GetPassIndex(pass); + plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); hsGMatState s; s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); - - if( s.fZFlags & hsGMatState::kZIncLayer ) + + if (s.fZFlags & hsGMatState::kZIncLayer) ISetLayer(1); else ISetLayer(0); IHandleZMode(s); IHandleBlendMode(s); - + if (s.fMiscFlags & hsGMatState::kMiscTwoSided) { - if(fState.fCurrentCullMode != MTL::CullModeNone) { + if (fState.fCurrentCullMode != MTL::CullModeNone) { fDevice.CurrentRenderCommandEncoder()->setCullMode(MTL::CullModeNone); - fState.fCurrentCullMode = MTL::CullModeNone; + fState.fCurrentCullMode = MTL::CullModeNone; } } else { ISetCullMode(); } - + //Some build passes don't allow shaders. Render the geometry and the provided material, but don't allow the shader path if instructed to. In the DX source, this would be done by the render phase setting the shaders to null after calling this. That won't work here in since our pipeline state has to know the shaders. - if(lay->GetVertexShader() && allowShaders) { - + if (lay->GetVertexShader() && allowShaders) { lay = IPushOverBaseLayer(lay); lay = IPushOverAllLayer(lay); - + //pure shader path - plShader *vertexShader = lay->GetVertexShader(); - plShader *fragShader = lay->GetPixelShader(); - + plShader* vertexShader = lay->GetVertexShader(); + plShader* fragShader = lay->GetPixelShader(); + fCurrLay = lay; fCurrNumLayers = mRef->fPassLengths[pass]; - + ISetShaders(vRef, s, vertexShader, fragShader); - + //FIXME: Programmable pipeline does not implement the full feature set /* The programmable pipeline doesn't do things like set the texture transform matrices, @@ -1570,7 +1562,7 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial *material, uint32_t pass, and the way it stores textures. So maybe things should be reconciled after that work is done. */ - + for (size_t i = 0; i < material->GetNumLayers(); i++) { plLayerInterface* layer = material->GetLayer(i); if (!layer) { @@ -1578,33 +1570,32 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial *material, uint32_t pass, } CheckTextureRef(layer); - + plBitmap* img = plBitmap::ConvertNoRef(layer->GetTexture()); if (!img) { return false; } - + plMetalTextureRef* texRef = (plMetalTextureRef*)img->GetDeviceRef(); if (!texRef->fTexture) { return false; } - + size_t idOffset = 0; //Metal doesn't like mixing 2D and cubic textures. If this is a cubic texture, make sure it lands in the right ID range. - if(plCubicRenderTarget::ConvertNoRef( img )) { + if (plCubicRenderTarget::ConvertNoRef(img)) { idOffset = FragmentShaderArgumentAttributeCubicTextures; } - + fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(texRef->fTexture, i + idOffset); - } lay = IPopOverAllLayer(lay); lay = IPopOverBaseLayer(lay); } else { //"Fixed" path - + /* To compute correct lighting we need to add the pushover layers. The actual renderer will do it's own add and remove, so remove the @@ -1613,85 +1604,81 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial *material, uint32_t pass, lay = IPushOverBaseLayer(lay); lay = IPushOverAllLayer(lay); ICalcLighting(mRef, lay, currSpan); - + s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); - + /* If the layer opacity is 0, don't draw it. This prevents it from contributing to the Z buffer. This can happen with some models like the fire marbles in the neighborhood that have some models for physics only, and then can block other rendering in the Z buffer. DX pipeline does this in ILoopOverLayers. */ - if( (s.fBlendFlags & hsGMatState::kBlendAlpha) - &&lay->GetOpacity() <= 0 - &&(fCurrLightingMethod != plSpan::kLiteVtxPreshaded) ) { - + if ((s.fBlendFlags & hsGMatState::kBlendAlpha) && lay->GetOpacity() <= 0 && (fCurrLightingMethod != plSpan::kLiteVtxPreshaded)) { //FIXME: All these popping of layers in the return sections is getting ugly - + lay = IPopOverAllLayer(lay); lay = IPopOverBaseLayer(lay); - + return false; } - + if (s.fBlendFlags & hsGMatState::kBlendInvertVtxAlpha) fCurrentRenderPassUniforms->invVtxAlpha = true; else fCurrentRenderPassUniforms->invVtxAlpha = false; - + std::vector& spanLights = currSpan->GetLightList(false); - + size_t numActivePiggyBacks = 0; - if( !(s.fMiscFlags & hsGMatState::kMiscBumpChans) && !(s.fShadeFlags & hsGMatState::kShadeEmissive) ) + if (!(s.fMiscFlags & hsGMatState::kMiscBumpChans) && !(s.fShadeFlags & hsGMatState::kShadeEmissive)) { /// Tack lightmap onto last stage if we have one numActivePiggyBacks = fActivePiggyBacks; - } - + struct plMetalFragmentShaderDescription fragmentShaderDescription; - + lay = IPopOverAllLayer(lay); lay = IPopOverBaseLayer(lay); - - if(numActivePiggyBacks==0 && fOverBaseLayer == nullptr && fOverAllLayer == nullptr) { + + if (numActivePiggyBacks == 0 && fOverBaseLayer == nullptr && fOverAllLayer == nullptr) { mRef->FastEncodeArguments(fDevice.CurrentRenderCommandEncoder(), fCurrentRenderPassUniforms, pass); - + fragmentShaderDescription = mRef->GetFragmentShaderDescription(pass); } else { - //Plasma pulls piggybacks from the rear first, pull the number of active piggybacks - auto firstPiggyback = fPiggyBackStack.end() - numActivePiggyBacks; - auto lastPiggyback = fPiggyBackStack.end(); + auto firstPiggyback = fPiggyBackStack.end() - numActivePiggyBacks; + auto lastPiggyback = fPiggyBackStack.end(); std::vector subPiggybacks(firstPiggyback, lastPiggyback); - mRef->EncodeArguments(fDevice.CurrentRenderCommandEncoder(), fCurrentRenderPassUniforms, pass, &fragmentShaderDescription, &subPiggybacks, - [&](plLayerInterface* layer, uint32_t index){ - if(index==0) { + mRef->EncodeArguments( + fDevice.CurrentRenderCommandEncoder(), fCurrentRenderPassUniforms, pass, &fragmentShaderDescription, &subPiggybacks, + [&](plLayerInterface* layer, uint32_t index) { + if (index == 0) { layer = IPushOverBaseLayer(layer); } layer = IPushOverAllLayer(layer); - + return layer; - }, - [&](plLayerInterface* layer, uint32_t index){ + }, + [&](plLayerInterface* layer, uint32_t index) { layer = IPopOverAllLayer(layer); - if(index==0) + if (index == 0) layer = IPopOverBaseLayer(layer); return layer; }); } - - plMetalDevice::plMetalLinkedPipeline *linkedPipeline = plMetalMaterialPassPipelineState(&fDevice, vRef, fragmentShaderDescription).GetRenderPipelineState(); - const MTL::RenderPipelineState *pipelineState = linkedPipeline->pipelineState; - + + plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalMaterialPassPipelineState(&fDevice, vRef, fragmentShaderDescription).GetRenderPipelineState(); + const MTL::RenderPipelineState* pipelineState = linkedPipeline->pipelineState; + /*plMetalDevice::plMetalLinkedPipeline *pipeline = fDevice.pipelineStateFor(vRef, s.fBlendFlags, numActivePiggyBacks + mRef->fPassLengths[pass], plShaderID::Unregistered, plShaderID::Unregistered, sources, blendModes, miscFlags); const MTL::RenderPipelineState *pipelineState = pipeline->pipelineState;*/ - if(fState.fCurrentPipelineState != pipelineState) { + if (fState.fCurrentPipelineState != pipelineState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(pipelineState); fState.fCurrentPipelineState = pipelineState; } } - + return true; } @@ -1706,51 +1693,42 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial *material, uint32_t pass, void plMetalPipeline::ISetPipeConsts(plShader* shader) { size_t n = shader->GetNumPipeConsts(); - int i; - for( i = 0; i < n; i++ ) + int i; + for (i = 0; i < n; i++) { const plPipeConst& pc = shader->GetPipeConst(i); - switch( pc.fType ) + switch (pc.fType) { - case plPipeConst::kFogSet: - { + case plPipeConst::kFogSet: { float set[4]; //FIXME: Fog broken in dynamic pipeline //IGetVSFogSet(set); //shader->SetFloat4(pc.fReg, set); - } - break; - case plPipeConst::kLayAmbient: - { + } break; + case plPipeConst::kLayAmbient: { hsColorRGBA col = fCurrLay->GetAmbientColor(); shader->SetColor(pc.fReg, col); - } - break; - case plPipeConst::kLayRuntime: - { + } break; + case plPipeConst::kLayRuntime: { hsColorRGBA col = fCurrLay->GetRuntimeColor(); col.a = fCurrLay->GetOpacity(); shader->SetColor(pc.fReg, col); - } - break; - case plPipeConst::kLaySpecular: - { + } break; + case plPipeConst::kLaySpecular: { hsColorRGBA col = fCurrLay->GetSpecularColor(); shader->SetColor(pc.fReg, col); - } - break; - case plPipeConst::kTex3x4_0: - case plPipeConst::kTex3x4_1: - case plPipeConst::kTex3x4_2: - case plPipeConst::kTex3x4_3: - case plPipeConst::kTex3x4_4: - case plPipeConst::kTex3x4_5: - case plPipeConst::kTex3x4_6: - case plPipeConst::kTex3x4_7: - { + } break; + case plPipeConst::kTex3x4_0: + case plPipeConst::kTex3x4_1: + case plPipeConst::kTex3x4_2: + case plPipeConst::kTex3x4_3: + case plPipeConst::kTex3x4_4: + case plPipeConst::kTex3x4_5: + case plPipeConst::kTex3x4_6: + case plPipeConst::kTex3x4_7: { int stage = pc.fType - plPipeConst::kTex3x4_0; - if( stage > fCurrNumLayers ) + if (stage > fCurrNumLayers) { // Ooops. This is bad, means the shader is expecting more layers than // we actually have (or is just bogus). Assert and quietly continue. @@ -1760,20 +1738,18 @@ void plMetalPipeline::ISetPipeConsts(plShader* shader) const hsMatrix44& xfm = fCurrMaterial->GetLayer(fCurrLayerIdx + stage)->GetTransform(); shader->SetMatrix34(pc.fReg, xfm); - } - break; - case plPipeConst::kTex2x4_0: - case plPipeConst::kTex2x4_1: - case plPipeConst::kTex2x4_2: - case plPipeConst::kTex2x4_3: - case plPipeConst::kTex2x4_4: - case plPipeConst::kTex2x4_5: - case plPipeConst::kTex2x4_6: - case plPipeConst::kTex2x4_7: - { + } break; + case plPipeConst::kTex2x4_0: + case plPipeConst::kTex2x4_1: + case plPipeConst::kTex2x4_2: + case plPipeConst::kTex2x4_3: + case plPipeConst::kTex2x4_4: + case plPipeConst::kTex2x4_5: + case plPipeConst::kTex2x4_6: + case plPipeConst::kTex2x4_7: { int stage = pc.fType - plPipeConst::kTex2x4_0; - if( stage > fCurrNumLayers ) + if (stage > fCurrNumLayers) { // Ooops. This is bad, means the shader is expecting more layers than // we actually have (or is just bogus). Assert and quietly continue. @@ -1783,20 +1759,18 @@ void plMetalPipeline::ISetPipeConsts(plShader* shader) const hsMatrix44& xfm = fCurrMaterial->GetLayer(fCurrLayerIdx + stage)->GetTransform(); shader->SetMatrix24(pc.fReg, xfm); - } - break; - case plPipeConst::kTex1x4_0: - case plPipeConst::kTex1x4_1: - case plPipeConst::kTex1x4_2: - case plPipeConst::kTex1x4_3: - case plPipeConst::kTex1x4_4: - case plPipeConst::kTex1x4_5: - case plPipeConst::kTex1x4_6: - case plPipeConst::kTex1x4_7: - { + } break; + case plPipeConst::kTex1x4_0: + case plPipeConst::kTex1x4_1: + case plPipeConst::kTex1x4_2: + case plPipeConst::kTex1x4_3: + case plPipeConst::kTex1x4_4: + case plPipeConst::kTex1x4_5: + case plPipeConst::kTex1x4_6: + case plPipeConst::kTex1x4_7: { int stage = pc.fType - plPipeConst::kTex1x4_0; - if( stage > fCurrNumLayers ) + if (stage > fCurrNumLayers) { // Ooops. This is bad, means the shader is expecting more layers than // we actually have (or is just bogus). Assert and quietly continue. @@ -1806,114 +1780,93 @@ void plMetalPipeline::ISetPipeConsts(plShader* shader) const hsMatrix44& xfm = fCurrMaterial->GetLayer(fCurrLayerIdx + stage)->GetTransform(); shader->SetFloat4(pc.fReg, xfm.fMap[0]); - } - break; - case plPipeConst::kLocalToNDC: - { + } break; + case plPipeConst::kLocalToNDC: { hsMatrix44 cam2ndc = IGetCameraToNDC(); hsMatrix44 world2cam = GetViewTransform().GetWorldToCamera(); hsMatrix44 local2ndc = cam2ndc * world2cam * GetLocalToWorld(); shader->SetMatrix44(pc.fReg, local2ndc); - } - break; + } break; - case plPipeConst::kCameraToNDC: - { + case plPipeConst::kCameraToNDC: { hsMatrix44 cam2ndc = IGetCameraToNDC(); shader->SetMatrix44(pc.fReg, cam2ndc); - } - break; + } break; - case plPipeConst::kWorldToNDC: - { + case plPipeConst::kWorldToNDC: { hsMatrix44 cam2ndc = IGetCameraToNDC(); hsMatrix44 world2cam = GetViewTransform().GetWorldToCamera(); hsMatrix44 world2ndc = cam2ndc * world2cam; shader->SetMatrix44(pc.fReg, world2ndc); - } - break; + } break; - case plPipeConst::kLocalToWorld: - shader->SetMatrix34(pc.fReg, GetLocalToWorld()); - break; + case plPipeConst::kLocalToWorld: + shader->SetMatrix34(pc.fReg, GetLocalToWorld()); + break; - case plPipeConst::kWorldToLocal: - shader->SetMatrix34(pc.fReg, GetWorldToLocal()); - break; + case plPipeConst::kWorldToLocal: + shader->SetMatrix34(pc.fReg, GetWorldToLocal()); + break; - case plPipeConst::kWorldToCamera: - { + case plPipeConst::kWorldToCamera: { hsMatrix44 world2cam = GetViewTransform().GetWorldToCamera(); shader->SetMatrix34(pc.fReg, world2cam); - } - break; + } break; - case plPipeConst::kCameraToWorld: - { + case plPipeConst::kCameraToWorld: { hsMatrix44 cam2world = GetViewTransform().GetCameraToWorld(); shader->SetMatrix34(pc.fReg, cam2world); - } - break; + } break; - case plPipeConst::kLocalToCamera: - { + case plPipeConst::kLocalToCamera: { hsMatrix44 world2cam = GetViewTransform().GetWorldToCamera(); hsMatrix44 local2cam = world2cam * GetLocalToWorld(); shader->SetMatrix34(pc.fReg, local2cam); - } - break; + } break; - case plPipeConst::kCameraToLocal: - { + case plPipeConst::kCameraToLocal: { hsMatrix44 cam2world = GetViewTransform().GetCameraToWorld(); hsMatrix44 cam2local = GetWorldToLocal() * cam2world; shader->SetMatrix34(pc.fReg, cam2local); - } - break; + } break; - case plPipeConst::kCamPosWorld: - { + case plPipeConst::kCamPosWorld: { shader->SetVectorW(pc.fReg, GetViewTransform().GetCameraToWorld().GetTranslate(), 1.f); - } - break; + } break; - case plPipeConst::kCamPosLocal: - { + case plPipeConst::kCamPosLocal: { hsPoint3 localCam = GetWorldToLocal() * GetViewTransform().GetCameraToWorld().GetTranslate(); shader->SetVectorW(pc.fReg, localCam, 1.f); - } - break; + } break; - case plPipeConst::kObjPosWorld: - { + case plPipeConst::kObjPosWorld: { shader->SetVectorW(pc.fReg, GetLocalToWorld().GetTranslate(), 1.f); - } - break; - - // UNIMPLEMENTED - case plPipeConst::kDirLight1: - case plPipeConst::kDirLight2: - case plPipeConst::kDirLight3: - case plPipeConst::kDirLight4: - case plPipeConst::kPointLight1: - case plPipeConst::kPointLight2: - case plPipeConst::kPointLight3: - case plPipeConst::kPointLight4: - case plPipeConst::kColorFilter: - case plPipeConst::kMaxType: - break; + } break; + + // UNIMPLEMENTED + case plPipeConst::kDirLight1: + case plPipeConst::kDirLight2: + case plPipeConst::kDirLight3: + case plPipeConst::kDirLight4: + case plPipeConst::kPointLight1: + case plPipeConst::kPointLight2: + case plPipeConst::kPointLight3: + case plPipeConst::kPointLight4: + case plPipeConst::kColorFilter: + case plPipeConst::kMaxType: + break; } } } @@ -1923,51 +1876,51 @@ void plMetalPipeline::ISetPipeConsts(plShader* shader) // be nil, in which case the fixed function pipeline is indicated. // Any Pipe Constants the non-FFP shader wants will be set here. // Lastly, all constants will be set (as a block) for any non-FFP vertex or pixel shader. -bool plMetalPipeline::ISetShaders(const plMetalVertexBufferRef * vRef, const hsGMatState blendMode, plShader* vShader, plShader* pShader) +bool plMetalPipeline::ISetShaders(const plMetalVertexBufferRef* vRef, const hsGMatState blendMode, plShader* vShader, plShader* pShader) { hsAssert(vShader, "Can't handle programmable passes without vShader"); hsAssert(pShader, "Can't handle programmable passes without pShader"); plShaderID::ID vertexShaderID = vShader->GetDecl()->GetID(); plShaderID::ID fragmentShaderID = pShader->GetDecl()->GetID(); - - plMetalDevice::plMetalLinkedPipeline *pipeline = plMetalDynamicMaterialPipelineState(&fDevice, vRef, blendMode.fBlendFlags, vertexShaderID, fragmentShaderID).GetRenderPipelineState(); - if(fState.fCurrentPipelineState != pipeline->pipelineState) { + + plMetalDevice::plMetalLinkedPipeline* pipeline = plMetalDynamicMaterialPipelineState(&fDevice, vRef, blendMode.fBlendFlags, vertexShaderID, fragmentShaderID).GetRenderPipelineState(); + if (fState.fCurrentPipelineState != pipeline->pipelineState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(pipeline->pipelineState); fState.fCurrentPipelineState = pipeline->pipelineState; } - - if( vShader ) + + if (vShader) { hsAssert(vShader->IsVertexShader(), "Wrong type shader as vertex shader"); ISetPipeConsts(vShader); - + plMetalVertexShader* vRef = (plMetalVertexShader*)vShader->GetDeviceRef(); - if( !vRef ) + if (!vRef) { vRef = new plMetalVertexShader(vShader); hsRefCnt_SafeUnRef(vRef); } - if( !vRef->IsLinked() ) + if (!vRef->IsLinked()) vRef->Link(&fVShaderRefList); - + vRef->ISetConstants(this); } - if( pShader ) + if (pShader) { hsAssert(pShader->IsPixelShader(), "Wrong type shader as pixel shader"); ISetPipeConsts(pShader); - + plMetalFragmentShader* pRef = (plMetalFragmentShader*)pShader->GetDeviceRef(); - if( !pRef ) + if (!pRef) { pRef = new plMetalFragmentShader(pShader); hsRefCnt_SafeUnRef(pRef); } - if( !pRef->IsLinked() ) + if (!pRef->IsLinked()) pRef->Link(&fPShaderRefList); - + pRef->ISetConstants(this); } @@ -2014,7 +1967,7 @@ bool plMetalPipeline::ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup if (vRef->Expired(fVtxRefTime)) { IRefreshDynVertices(group, vRef); //fDevice.GetCurrentCommandBuffer()->addCompletedHandler( ^(MTL::CommandBuffer *buffer) { - //vRef->fVertexBuffer->setPurgeableState(MTL::PurgeableStateVolatile); + //vRef->fVertexBuffer->setPurgeableState(MTL::PurgeableStateVolatile); //}); } @@ -2023,14 +1976,14 @@ bool plMetalPipeline::ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup iRef->SetRebuiltSinceUsed(true); } - return false; // No error + return false; // No error } bool plMetalPipeline::IRefreshDynVertices(plGBufferGroup* group, plMetalVertexBufferRef* vRef) { ptrdiff_t size = (group->GetVertBufferEnd(vRef->fIndex) - group->GetVertBufferStart(vRef->fIndex)) * vRef->fVertexSize; if (!size) - return false; // No error, just nothing to do. + return false; // No error, just nothing to do. hsAssert(size > 0, "Bad start and end counts in a group"); @@ -2044,14 +1997,14 @@ bool plMetalPipeline::IRefreshDynVertices(plGBufferGroup* group, plMetalVertexBu vData = vRef->fData; else vData = group->GetVertBufferData(vRef->fIndex) + group->GetVertBufferStart(vRef->fIndex) * vRef->fVertexSize; - + vRef->PrepareForWrite(); MTL::Buffer* vertexBuffer = vRef->GetBuffer(); - if(!vertexBuffer || vertexBuffer->length() < size) { + if (!vertexBuffer || vertexBuffer->length() < size) { //Plasma will present different length buffers at different times vertexBuffer = fDevice.fMetalDevice->newBuffer(vData, size, MTL::ResourceStorageModeManaged)->autorelease(); - if(vRef->Volatile()) { + if (vRef->Volatile()) { fDevice.GetCurrentCommandBuffer()->addCompletedHandler(^(MTL::CommandBuffer* buffer){ //vRef->fVertexBuffer->setPurgeableState(MTL::PurgeableStateVolatile); }); @@ -2073,12 +2026,12 @@ bool plMetalPipeline::IRefreshDynVertices(plGBufferGroup* group, plMetalVertexBu void plMetalPipeline::IHandleZMode(hsGMatState flags) { //Metal is very particular that if there is no depth buffer we need to explictly disable z read and write - if(fDevice.fCurrentDepthFormat == MTL::PixelFormatInvalid) { + if (fDevice.fCurrentDepthFormat == MTL::PixelFormatInvalid) { fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(fDevice.fNoZReadOrWriteStencilState); return; } - - MTL::DepthStencilState *newDepthState; + + MTL::DepthStencilState* newDepthState; switch (flags.fZFlags & hsGMatState::kZMask) { case hsGMatState::kZClearZ: @@ -2104,8 +2057,8 @@ void plMetalPipeline::IHandleZMode(hsGMatState flags) hsAssert(false, "Illegal combination of Z Buffer modes (Clear but don't write)"); break; } - - if(fState.fCurrentDepthStencilState != newDepthState) { + + if (fState.fCurrentDepthStencilState != newDepthState) { fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(newDepthState); fState.fCurrentDepthStencilState = newDepthState; } @@ -2114,11 +2067,11 @@ void plMetalPipeline::IHandleZMode(hsGMatState flags) //// ISetLayer //////////////////////////////////////////////////////////////// // Sets whether we're rendering a base layer or upper layer. Upper layer has // a Z bias to avoid Z fighting. -void plMetalPipeline::ISetLayer( uint32_t lay ) +void plMetalPipeline::ISetLayer(uint32_t lay) { - if( lay ) + if (lay) { - if( fCurrRenderLayer != lay ) + if (fCurrRenderLayer != lay) { fCurrRenderLayer = lay; @@ -2128,8 +2081,7 @@ void plMetalPipeline::ISetLayer( uint32_t lay ) static float max [[gnu::used]] = -0.00001; fDevice.CurrentRenderCommandEncoder()->setDepthBias(constBias, mult, max); } - } - else if( fCurrRenderLayer != 0 ) + } else if (fCurrRenderLayer != 0) { fCurrRenderLayer = 0; fDevice.CurrentRenderCommandEncoder()->setDepthBias(0.0, 0.0, 0.0); @@ -2197,25 +2149,22 @@ void plMetalPipeline::IHandleBlendMode(hsGMatState flags) //printf("glBlendFunc(GL_ONE, GL_ZERO);\n"); break; - default: + default: { + hsAssert(false, "Too many blend modes specified in material"); + plLayer* lay = plLayer::ConvertNoRef(fCurrMaterial->GetLayer(fCurrLayerIdx)->BottomOfStack()); + if (lay) { - hsAssert(false, "Too many blend modes specified in material"); - plLayer* lay = plLayer::ConvertNoRef(fCurrMaterial->GetLayer(fCurrLayerIdx)->BottomOfStack()); - if( lay ) + if (lay->GetBlendFlags() & hsGMatState::kBlendAlpha) { - if( lay->GetBlendFlags() & hsGMatState::kBlendAlpha ) - { - lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAlpha); - } - else - { - lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAdd); - } + lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAlpha); + } else + { + lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAdd); } - //layer state needs to be syncronized to the GPU - static_cast(fCurrMaterial->GetDeviceRef())->SetDirty(true); } - break; + //layer state needs to be syncronized to the GPU + static_cast(fCurrMaterial->GetDeviceRef())->SetDirty(true); + } break; } } } @@ -2226,16 +2175,16 @@ void plMetalPipeline::ICalcLighting(plMetalMaterialShaderRef* mRef, const plLaye if (IsDebugFlagSet(plPipeDbg::kFlagAllBright)) { - fCurrentRenderPassUniforms->globalAmb = { 1.0, 1.0, 1.0, 1.0 }; + fCurrentRenderPassUniforms->globalAmb = {1.0, 1.0, 1.0, 1.0}; - fCurrentRenderPassUniforms->ambientCol = { 1.0, 1.0, 1.0 }; - fCurrentRenderPassUniforms->diffuseCol = { 1.0, 1.0, 1.0, 1.0 }; - fCurrentRenderPassUniforms->emissiveCol = { 1.0, 1.0, 1.0 }; - fCurrentRenderPassUniforms->emissiveCol = { 1.0, 1.0, 1.0 }; - fCurrentRenderPassUniforms->specularCol = { 1.0, 1.0, 1.0 }; + fCurrentRenderPassUniforms->ambientCol = {1.0, 1.0, 1.0}; + fCurrentRenderPassUniforms->diffuseCol = {1.0, 1.0, 1.0, 1.0}; + fCurrentRenderPassUniforms->emissiveCol = {1.0, 1.0, 1.0}; + fCurrentRenderPassUniforms->emissiveCol = {1.0, 1.0, 1.0}; + fCurrentRenderPassUniforms->specularCol = {1.0, 1.0, 1.0}; - fCurrentRenderPassUniforms->ambientSrc = 1.0; - fCurrentRenderPassUniforms->diffuseSrc = 1.0; + fCurrentRenderPassUniforms->ambientSrc = 1.0; + fCurrentRenderPassUniforms->diffuseSrc = 1.0; fCurrentRenderPassUniforms->emissiveSrc = 1.0; fCurrentRenderPassUniforms->specularSrc = 1.0; @@ -2254,40 +2203,40 @@ void plMetalPipeline::ICalcLighting(plMetalMaterialShaderRef* mRef, const plLaye /// Select one of our three lighting methods switch (mode) { - case plSpan::kLiteMaterial: // Material shading + case plSpan::kLiteMaterial: // Material shading { if (state.fShadeFlags & hsGMatState::kShadeWhite) { - fCurrentRenderPassUniforms->globalAmb = { 1.0, 1.0, 1.0, 1.0 }; - fCurrentRenderPassUniforms->ambientCol = { 1.0, 1.0, 1.0 }; + fCurrentRenderPassUniforms->globalAmb = {1.0, 1.0, 1.0, 1.0}; + fCurrentRenderPassUniforms->ambientCol = {1.0, 1.0, 1.0}; } else if (IsDebugFlagSet(plPipeDbg::kFlagNoPreShade)) { - fCurrentRenderPassUniforms->globalAmb = { 0.0, 0.0, 0.0, 1.0 }; - fCurrentRenderPassUniforms->ambientCol = { 0.0, 0.0, 0.0 }; + fCurrentRenderPassUniforms->globalAmb = {0.0, 0.0, 0.0, 1.0}; + fCurrentRenderPassUniforms->ambientCol = {0.0, 0.0, 0.0}; } else { hsColorRGBA amb = currLayer->GetPreshadeColor(); - fCurrentRenderPassUniforms->globalAmb = { static_cast(amb.r), static_cast(amb.g), static_cast(amb.b), 1.0 }; - fCurrentRenderPassUniforms->ambientCol = { static_cast(amb.r), static_cast(amb.g), static_cast(amb.b) }; + fCurrentRenderPassUniforms->globalAmb = {static_cast(amb.r), static_cast(amb.g), static_cast(amb.b), 1.0}; + fCurrentRenderPassUniforms->ambientCol = {static_cast(amb.r), static_cast(amb.g), static_cast(amb.b)}; } hsColorRGBA dif = currLayer->GetRuntimeColor(); - fCurrentRenderPassUniforms->diffuseCol = { static_cast(dif.r), static_cast(dif.g), static_cast(dif.b), static_cast(currLayer->GetOpacity()) }; + fCurrentRenderPassUniforms->diffuseCol = {static_cast(dif.r), static_cast(dif.g), static_cast(dif.b), static_cast(currLayer->GetOpacity())}; hsColorRGBA em = currLayer->GetAmbientColor(); - fCurrentRenderPassUniforms->emissiveCol = { static_cast(em.r), static_cast(em.g), static_cast(em.b) }; + fCurrentRenderPassUniforms->emissiveCol = {static_cast(em.r), static_cast(em.g), static_cast(em.b)}; // Set specular properties if (state.fShadeFlags & hsGMatState::kShadeSpecular) { hsColorRGBA spec = currLayer->GetSpecularColor(); - fCurrentRenderPassUniforms->specularCol = { static_cast(spec.r), static_cast(spec.g), static_cast(spec.b) }; + fCurrentRenderPassUniforms->specularCol = {static_cast(spec.r), static_cast(spec.g), static_cast(spec.b)}; #if 0 mat.Power = currLayer->GetSpecularPower(); #endif } else { - fCurrentRenderPassUniforms->specularCol = { 0.0, 0.0, 0.0 }; + fCurrentRenderPassUniforms->specularCol = {0.0, 0.0, 0.0}; } fCurrentRenderPassUniforms->diffuseSrc = 1.0; fCurrentRenderPassUniforms->emissiveSrc = 1.0; - fCurrentRenderPassUniforms -> specularSrc = 1.0; + fCurrentRenderPassUniforms->specularSrc = 1.0; if (state.fShadeFlags & hsGMatState::kShadeNoShade) { fCurrentRenderPassUniforms->ambientSrc = 1.0; @@ -2301,11 +2250,11 @@ void plMetalPipeline::ICalcLighting(plMetalMaterialShaderRef* mRef, const plLaye case plSpan::kLiteVtxPreshaded: // Vtx preshaded { - fCurrentRenderPassUniforms->globalAmb = { 0.0, 0.0, 0.0 }; - fCurrentRenderPassUniforms->ambientCol = { 0.0, 0.0, 0.0 }; - fCurrentRenderPassUniforms->diffuseCol = { 0.0, 0.0, 0.0, 0.0 }; - fCurrentRenderPassUniforms->emissiveCol = { 0.0, 0.0, 0.0 }; - fCurrentRenderPassUniforms->specularCol = { 0.0, 0.0, 0.0 }; + fCurrentRenderPassUniforms->globalAmb = {0.0, 0.0, 0.0}; + fCurrentRenderPassUniforms->ambientCol = {0.0, 0.0, 0.0}; + fCurrentRenderPassUniforms->diffuseCol = {0.0, 0.0, 0.0, 0.0}; + fCurrentRenderPassUniforms->emissiveCol = {0.0, 0.0, 0.0}; + fCurrentRenderPassUniforms->specularCol = {0.0, 0.0, 0.0}; fCurrentRenderPassUniforms->diffuseSrc = 0.0; fCurrentRenderPassUniforms->ambientSrc = 1.0; @@ -2316,87 +2265,84 @@ void plMetalPipeline::ICalcLighting(plMetalMaterialShaderRef* mRef, const plLaye } else { fCurrentRenderPassUniforms->emissiveSrc = 1.0; } - + fCurrLightingMethod = plSpan::kLiteVtxPreshaded; break; } - case plSpan::kLiteVtxNonPreshaded: // Vtx non-preshaded + case plSpan::kLiteVtxNonPreshaded: // Vtx non-preshaded { - fCurrentRenderPassUniforms->ambientCol = { 0.0, 0.0, 0.0 }; - fCurrentRenderPassUniforms->diffuseCol = { 0.0, 0.0, 0.0, 0.0 }; + fCurrentRenderPassUniforms->ambientCol = {0.0, 0.0, 0.0}; + fCurrentRenderPassUniforms->diffuseCol = {0.0, 0.0, 0.0, 0.0}; hsColorRGBA em = currLayer->GetAmbientColor(); - fCurrentRenderPassUniforms->emissiveCol = { static_cast(em.r), static_cast(em.g), static_cast(em.b) }; + fCurrentRenderPassUniforms->emissiveCol = {static_cast(em.r), static_cast(em.g), static_cast(em.b)}; // Set specular properties if (state.fShadeFlags & hsGMatState::kShadeSpecular) { hsColorRGBA spec = currLayer->GetSpecularColor(); - fCurrentRenderPassUniforms->specularCol = { static_cast(spec.r), static_cast(spec.g), static_cast(spec.b) }; + fCurrentRenderPassUniforms->specularCol = {static_cast(spec.r), static_cast(spec.g), static_cast(spec.b)}; #if 0 mat.Power = currLayer->GetSpecularPower(); #endif } else { - fCurrentRenderPassUniforms->specularCol = { 0.0, 0.0, 0.0 }; + fCurrentRenderPassUniforms->specularCol = {0.0, 0.0, 0.0}; } hsColorRGBA amb = currLayer->GetPreshadeColor(); - fCurrentRenderPassUniforms->globalAmb = { static_cast(amb.r), static_cast(amb.g), static_cast(amb.b), static_cast(amb.a) }; + fCurrentRenderPassUniforms->globalAmb = {static_cast(amb.r), static_cast(amb.g), static_cast(amb.b), static_cast(amb.a)}; fCurrentRenderPassUniforms->ambientSrc = 0.0; fCurrentRenderPassUniforms->diffuseSrc = 0.0; fCurrentRenderPassUniforms->emissiveSrc = 1.0; fCurrentRenderPassUniforms->specularSrc = 1.0; - + fCurrLightingMethod = plSpan::kLiteVtxNonPreshaded; break; } } // Piggy-back some temporary fog stuff on the lighting... const plFogEnvironment* fog = (currSpan ? (currSpan->fFogEnvironment ? currSpan->fFogEnvironment : &fView.GetDefaultFog()) : nullptr); - + if (currLayer) { if ((currLayer->GetShadeFlags() & hsGMatState::kShadeReallyNoFog) && !(fMatOverOff.fShadeFlags & hsGMatState::kShadeReallyNoFog)) fog = nil; } - - uint8_t type = fog ? fog->GetType() : plFogEnvironment::kNoFog; + + uint8_t type = fog ? fog->GetType() : plFogEnvironment::kNoFog; hsColorRGBA color; switch (type) { - case plFogEnvironment::kLinearFog: - { + case plFogEnvironment::kLinearFog: { float start, end; fog->GetPipelineParams(&start, &end, &color); fCurrentRenderPassUniforms->fogExponential = 0; fCurrentRenderPassUniforms->fogValues = {start, end}; - fCurrentRenderPassUniforms->fogColor = { static_cast(color.r), static_cast(color.g), static_cast(color.b) }; + fCurrentRenderPassUniforms->fogColor = {static_cast(color.r), static_cast(color.g), static_cast(color.b)}; break; } case plFogEnvironment::kExpFog: - case plFogEnvironment::kExp2Fog: - { + case plFogEnvironment::kExp2Fog: { float density; float power = (type == plFogEnvironment::kExp2Fog) ? 2.0f : 1.0f; fog->GetPipelineParams(&density, &color); fCurrentRenderPassUniforms->fogExponential = 1; - fCurrentRenderPassUniforms->fogValues = { power, density}; - fCurrentRenderPassUniforms->fogColor = { static_cast(color.r), static_cast(color.g), static_cast(color.b) }; + fCurrentRenderPassUniforms->fogValues = {power, density}; + fCurrentRenderPassUniforms->fogColor = {static_cast(color.r), static_cast(color.g), static_cast(color.b)}; break; } default: fCurrentRenderPassUniforms->fogExponential = 0; - fCurrentRenderPassUniforms->fogValues = { 0.0, 0.0 }; - fCurrentRenderPassUniforms->fogColor = { 0.0, 0.0, 0.0 }; + fCurrentRenderPassUniforms->fogValues = {0.0, 0.0}; + fCurrentRenderPassUniforms->fogColor = {0.0, 0.0, 0.0}; break; } - - - if( currLayer->GetBlendFlags() & (hsGMatState::kBlendAdd | hsGMatState::kBlendMADD | hsGMatState::kBlendAddColorTimesAlpha) ) { - fCurrentRenderPassUniforms->fogColor = { 0.0, 0.0, 0.0 }; + + if (currLayer->GetBlendFlags() & (hsGMatState::kBlendAdd | hsGMatState::kBlendMADD | hsGMatState::kBlendAddColorTimesAlpha)) { + fCurrentRenderPassUniforms->fogColor = {0.0, 0.0, 0.0}; } } @@ -2406,16 +2352,16 @@ void plMetalPipeline::ICalcLighting(plMetalMaterialShaderRef* mRef, const plLaye // strongest N changes membership. void plMetalPipeline::ISelectLights(const plSpan* span, plMetalMaterialShaderRef* mRef, bool proj) { - const size_t numLights = kMetalMaxLightCount; - int32_t i = 0; - int32_t startScale; - float threshhold; - float overHold = 0.3; - float scale; - static std::vector onLights; + const size_t numLights = kMetalMaxLightCount; + int32_t i = 0; + int32_t startScale; + float threshhold; + float overHold = 0.3; + float scale; + static std::vector onLights; onLights.clear(); - if (!IsDebugFlagSet(plPipeDbg::kFlagNoRuntimeLights) && + if (!IsDebugFlagSet(plPipeDbg::kFlagNoRuntimeLights) && !(IsDebugFlagSet(plPipeDbg::kFlagNoApplyProjLights) && proj) && !(IsDebugFlagSet(plPipeDbg::kFlagOnlyApplyProjLights) && !proj)) { @@ -2424,7 +2370,7 @@ void plMetalPipeline::ISelectLights(const plSpan* span, plMetalMaterialShaderRef fLights.count = 0; for (i = 0; i < spanLights.size() && i < numLights; i++) { // If these are non-projected lights, go ahead and enable them. - if( !proj ) + if (!proj) { IEnableLight(fLights.count, spanLights[i]); fLights.count++; @@ -2459,15 +2405,15 @@ void plMetalPipeline::ISelectLights(const plSpan* span, plMetalMaterialShaderRef IScaleLight(i, span->GetLightScale(i, proj)); } } - + // For the projected lights, don't enable, just remember who they are. - if( proj ) + if (proj) { fProjAll.clear(); fProjEach.clear(); - for( i = 0; i < onLights.size(); i++ ) + for (i = 0; i < onLights.size(); i++) { - if( onLights[i]->OverAll() ) + if (onLights[i]->OverAll()) fProjAll.emplace_back(onLights[i]); else fProjEach.emplace_back(onLights[i]); @@ -2479,67 +2425,65 @@ void plMetalPipeline::ISelectLights(const plSpan* span, plMetalMaterialShaderRef void plMetalPipeline::IEnableLight(size_t i, plLightInfo* light) { hsColorRGBA amb = light->GetAmbient(); - fLights.lampSources[i].ambient = { static_cast(amb.r), static_cast(amb.g), static_cast(amb.b), static_cast(amb.a) }; + fLights.lampSources[i].ambient = {static_cast(amb.r), static_cast(amb.g), static_cast(amb.b), static_cast(amb.a)}; hsColorRGBA diff = light->GetDiffuse(); - fLights.lampSources[i].diffuse = { static_cast(diff.r), static_cast(diff.g), static_cast(diff.b), static_cast(diff.a) }; + fLights.lampSources[i].diffuse = {static_cast(diff.r), static_cast(diff.g), static_cast(diff.b), static_cast(diff.a)}; hsColorRGBA spec = light->GetSpecular(); - fLights.lampSources[i].specular = { static_cast(spec.r), static_cast(spec.g), static_cast(spec.b), static_cast(spec.a) }; + fLights.lampSources[i].specular = {static_cast(spec.r), static_cast(spec.g), static_cast(spec.b), static_cast(spec.a)}; plDirectionalLightInfo* dirLight = nullptr; - plOmniLightInfo* omniLight = nullptr; - plSpotLightInfo* spotLight = nullptr; + plOmniLightInfo* omniLight = nullptr; + plSpotLightInfo* spotLight = nullptr; if ((dirLight = plDirectionalLightInfo::ConvertNoRef(light)) != nullptr) { hsVector3 lightDir = dirLight->GetWorldDirection(); - fLights.lampSources[i].position = { lightDir.fX, lightDir.fY, lightDir.fZ, 0.0 }; - fLights.lampSources[i].direction = { lightDir.fX, lightDir.fY, lightDir.fZ }; + fLights.lampSources[i].position = {lightDir.fX, lightDir.fY, lightDir.fZ, 0.0}; + fLights.lampSources[i].direction = {lightDir.fX, lightDir.fY, lightDir.fZ}; fLights.lampSources[i].constAtten = 1.0f; fLights.lampSources[i].linAtten = 0.0f; fLights.lampSources[i].quadAtten = 0.0f; - } - else if ((omniLight = plOmniLightInfo::ConvertNoRef(light)) != nullptr) + } else if ((omniLight = plOmniLightInfo::ConvertNoRef(light)) != nullptr) { hsPoint3 pos = omniLight->GetWorldPosition(); - fLights.lampSources[i].position = { pos.fX, pos.fY, pos.fZ, 1.0 }; + fLights.lampSources[i].position = {pos.fX, pos.fY, pos.fZ, 1.0}; // TODO: Maximum Range - + fLights.lampSources[i].constAtten = omniLight->GetConstantAttenuation(); fLights.lampSources[i].linAtten = omniLight->GetLinearAttenuation(); fLights.lampSources[i].quadAtten = omniLight->GetQuadraticAttenuation(); if (!omniLight->GetProjection() && (spotLight = plSpotLightInfo::ConvertNoRef(omniLight)) != nullptr) { hsVector3 lightDir = spotLight->GetWorldDirection(); - fLights.lampSources[i].direction = { lightDir.fX, lightDir.fY, lightDir.fZ }; + fLights.lampSources[i].direction = {lightDir.fX, lightDir.fY, lightDir.fZ}; float falloff = spotLight->GetFalloff(); float gamma = cosf(spotLight->GetSpotInner()); float phi = cosf(spotLight->GetProjection() ? hsConstants::half_pi : spotLight->GetSpotOuter()); - fLights.lampSources[i].spotProps = { falloff, gamma, phi }; + fLights.lampSources[i].spotProps = {falloff, gamma, phi}; } else { - fLights.lampSources[i].spotProps = { 0.0, 0.0, 0.0 }; + fLights.lampSources[i].spotProps = {0.0, 0.0, 0.0}; } - } - else { + } else { IDisableLight(i); } } void plMetalPipeline::IDisableLight(size_t i) { - fLights.lampSources[i].position = { 0.0f, 0.0f, 0.0f, 0.0f }; - fLights.lampSources[i].ambient = { 0.0f, 0.0f, 0.0f, 0.0f }; - fLights.lampSources[i].diffuse = { 0.0f, 0.0f, 0.0f, 0.0f }; - fLights.lampSources[i].specular = { 0.0f, 0.0f, 0.0f, 0.0f }; - fLights.lampSources[i].constAtten = { 1.0f }; - fLights.lampSources[i].linAtten = { 0.0f }; - fLights.lampSources[i].quadAtten = { 0.0f }; - fLights.lampSources[i].scale = { 0.0f }; + fLights.lampSources[i].position = {0.0f, 0.0f, 0.0f, 0.0f}; + fLights.lampSources[i].ambient = {0.0f, 0.0f, 0.0f, 0.0f}; + fLights.lampSources[i].diffuse = {0.0f, 0.0f, 0.0f, 0.0f}; + fLights.lampSources[i].specular = {0.0f, 0.0f, 0.0f, 0.0f}; + fLights.lampSources[i].constAtten = {1.0f}; + fLights.lampSources[i].linAtten = {0.0f}; + fLights.lampSources[i].quadAtten = {0.0f}; + fLights.lampSources[i].scale = {0.0f}; } void plMetalPipeline::IScaleLight(size_t i, float scale) @@ -2550,20 +2494,20 @@ void plMetalPipeline::IScaleLight(size_t i, float scale) void plMetalPipeline::IDrawPlate(plPlate* plate) { - if(!plate->IsVisible()) { + if (!plate->IsVisible()) { return; } hsGMaterial* material = plate->GetMaterial(); - + plLayerInterface* lay = material->GetLayer(0); - hsGMatState s; + hsGMatState s; s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); IHandleZMode(s); IHandleBlendMode(s); fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(fDevice.fNoZReadOrWriteStencilState); fState.fCurrentDepthStencilState = fDevice.fNoZReadOrWriteStencilState; - + simd_float4x4 projMat = matrix_identity_float4x4; /// Set up the transform directly @@ -2582,15 +2526,15 @@ void plMetalPipeline::IDrawPlate(plPlate* plate) if (!mRef->IsLinked()) { mRef->Link(&fMatRefList); } - + fDevice.SetLocalToWorldMatrix(plate->GetTransform()); - - plMetalPlateManager *pm = (plMetalPlateManager *)fPlateMgr; - - plMetalPlatePipelineState state(&fDevice); + + plMetalPlateManager* pm = (plMetalPlateManager*)fPlateMgr; + + plMetalPlatePipelineState state(&fDevice); plMetalDevice::plMetalLinkedPipeline* linkedPipeline = state.GetRenderPipelineState(); - - if(fState.fCurrentPipelineState != linkedPipeline->pipelineState) { + + if (fState.fCurrentPipelineState != linkedPipeline->pipelineState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(linkedPipeline->pipelineState); fState.fCurrentPipelineState = linkedPipeline->pipelineState; } @@ -2598,32 +2542,31 @@ void plMetalPipeline::IDrawPlate(plPlate* plate) fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&alpha, sizeof(float), 6); fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(pm->fDepthState); fDevice.CurrentRenderCommandEncoder()->setCullMode(MTL::CullModeNone); - - int uniformSize = sizeof(VertexUniforms); + + int uniformSize = sizeof(VertexUniforms); VertexUniforms uniforms; uniforms.projectionMatrix = projMat; matrix_float4x4 modelMatrix; uniforms.worldToCameraMatrix = modelMatrix; uniforms.uvTransforms[0].UVWSrc = 0; //uniforms.worldToLocalMatrix = fDevice.fMatrixW2L; - + //flip world to camera, it's upside down matrix_float4x4 flip = matrix_identity_float4x4; flip.columns[1][1] = -1.0f; - - + //uniforms.worldToCameraMatrix = //uniforms.cameraToWorldMatrix = fDevice.fMatrixC2W; uniforms.localToWorldMatrix = matrix_multiply(flip, fDevice.fMatrixL2W); - + mRef->FastEncodeArguments(fDevice.CurrentRenderCommandEncoder(), &uniforms, 0); //FIXME: Hacking the old texture drawing into the plate path mRef->prepareTextures(fDevice.CurrentRenderCommandEncoder(), 0); - - fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&uniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms); - + + fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&uniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms); + pm->EncodeDraw(fDevice.CurrentRenderCommandEncoder()); - + IPopPiggyBacks(); } @@ -2634,7 +2577,7 @@ void plMetalPipeline::IDrawPlate(plPlate* plate) //we'll just let them push/pop the current state. void plMetalPipeline::PushCurrentLightSources() { - plMetalLights *lightSources = new plMetalLights(); + plMetalLights* lightSources = new plMetalLights(); memcpy(lightSources, &fLights, sizeof(plMetalLights)); fLightSourceStack.emplace_back(lightSources); } @@ -2642,7 +2585,7 @@ void plMetalPipeline::PushCurrentLightSources() void plMetalPipeline::PopCurrentLightSources() { hsAssert(fLightSourceStack.size() > 0, "Asked to pop light sources but none on stack"); - plMetalLights *lightSources = fLightSourceStack.back(); + plMetalLights* lightSources = fLightSourceStack.back(); fLightSourceStack.pop_back(); memcpy(&fLights, lightSources, sizeof(plMetalLights)); delete lightSources; @@ -2659,12 +2602,12 @@ void plMetalPipeline::PopCurrentLightSources() // Must be matched with call to IPopOverBaseLayer. plLayerInterface* plMetalPipeline::IPushOverBaseLayer(plLayerInterface* li) { - if( !li ) + if (!li) return nil; fOverLayerStack.emplace_back(li); - if( !fOverBaseLayer ) + if (!fOverBaseLayer) return fOverBaseLayer = li; fForceMatHandle = true; @@ -2678,7 +2621,7 @@ plLayerInterface* plMetalPipeline::IPushOverBaseLayer(plLayerInterface* li) // Should match calls to IPushOverBaseLayer. plLayerInterface* plMetalPipeline::IPopOverBaseLayer(plLayerInterface* li) { - if( !li ) + if (!li) return nil; fForceMatHandle = true; @@ -2696,12 +2639,12 @@ plLayerInterface* plMetalPipeline::IPopOverBaseLayer(plLayerInterface* li) // Must be matched by call to IPopOverAllLayer plLayerInterface* plMetalPipeline::IPushOverAllLayer(plLayerInterface* li) { - if( !li ) + if (!li) return nil; fOverLayerStack.push_back(li); - if( !fOverAllLayer ) + if (!fOverAllLayer) { fOverAllLayer = li; fOverAllLayer->Eval(fTime, fFrame, 0); @@ -2720,7 +2663,7 @@ plLayerInterface* plMetalPipeline::IPushOverAllLayer(plLayerInterface* li) // Should match calls to IPushOverAllLayer. plLayerInterface* plMetalPipeline::IPopOverAllLayer(plLayerInterface* li) { - if( !li ) + if (!li) return nil; fForceMatHandle = true; @@ -2736,7 +2679,7 @@ plLayerInterface* plMetalPipeline::IPopOverAllLayer(plLayerInterface* li) // Push a projected texture on as a piggy back. void plMetalPipeline::IPushProjPiggyBack(plLayerInterface* li) { - if( fView.fRenderState & plPipeline::kRenderNoPiggyBacks ) + if (fView.fRenderState & plPipeline::kRenderNoPiggyBacks) return; fPiggyBackStack.push_back(li); @@ -2748,7 +2691,7 @@ void plMetalPipeline::IPushProjPiggyBack(plLayerInterface* li) // Remove a projected texture from use as a piggy back. void plMetalPipeline::IPopProjPiggyBacks() { - if( fView.fRenderState & plPipeline::kRenderNoPiggyBacks ) + if (fView.fRenderState & plPipeline::kRenderNoPiggyBacks) return; fPiggyBackStack.resize(fMatPiggyBacks); @@ -2764,17 +2707,16 @@ void plMetalPipeline::IPushPiggyBacks(hsGMaterial* mat) { hsAssert(!fMatPiggyBacks, "Push/Pop Piggy mismatch"); - if( fView.fRenderState & plPipeline::kRenderNoPiggyBacks ) + if (fView.fRenderState & plPipeline::kRenderNoPiggyBacks) return; int i; - for( i = 0; i < mat->GetNumPiggyBacks(); i++ ) + for (i = 0; i < mat->GetNumPiggyBacks(); i++) { - if( !mat->GetPiggyBack(i) ) + if (!mat->GetPiggyBack(i)) continue; - if ((mat->GetPiggyBack(i)->GetMiscFlags() & hsGMatState::kMiscLightMap) - && IsDebugFlagSet(plPipeDbg::kFlagNoLightmaps)) + if ((mat->GetPiggyBack(i)->GetMiscFlags() & hsGMatState::kMiscLightMap) && IsDebugFlagSet(plPipeDbg::kFlagNoLightmaps)) continue; fPiggyBackStack.push_back(mat->GetPiggyBack(i)); @@ -2789,7 +2731,7 @@ void plMetalPipeline::IPushPiggyBacks(hsGMaterial* mat) // Matches IPushPiggyBacks. void plMetalPipeline::IPopPiggyBacks() { - if( fView.fRenderState & plPipeline::kRenderNoPiggyBacks ) + if (fView.fRenderState & plPipeline::kRenderNoPiggyBacks) return; fPiggyBackStack.resize(fPiggyBackStack.size() - fMatPiggyBacks); @@ -2816,7 +2758,8 @@ size_t plMetalPipeline::ISetNumActivePiggyBacks() return fActivePiggyBacks = std::min(fMaxPiggyBacks, uint32_t(fPiggyBackStack.size())); } -struct plAVTexVert { +struct plAVTexVert +{ float fPos[2]; float fUv[2]; }; @@ -2833,8 +2776,8 @@ void plMetalPipeline::IPreprocessAvatarTextures() if (fClothingOutfits.size() == 0) return; - - plMipmap *itemBufferTex = nullptr; + + plMipmap* itemBufferTex = nullptr; for (size_t oIdx = 0; oIdx < fClothingOutfits.size(); oIdx++) { plClothingOutfit* co = fClothingOutfits[oIdx]; @@ -2859,23 +2802,23 @@ void plMetalPipeline::IPreprocessAvatarTextures() PushRenderTarget(rt); fDevice.CurrentRenderCommandEncoder()->setViewport({0, 0, static_cast(rt->GetWidth()), static_cast(rt->GetHeight()), 0.f, 1.f}); - + static MTL::RenderPipelineState* baseAvatarRenderState = nullptr; static MTL::RenderPipelineState* avatarRenderState = nullptr; - + if (!baseAvatarRenderState) { //This is a bit of a hack, this really should be part of the plMetalDevice's function map. //But that hash map assumes that it follows the vertex arrangement of the models. //After a refactor, this function creation should go there. MTL::RenderPipelineDescriptor* descriptor = MTL::RenderPipelineDescriptor::alloc()->init()->autorelease(); - MTL::Library* library = fDevice.fMetalDevice->newDefaultLibrary()->autorelease(); - + MTL::Library* library = fDevice.fMetalDevice->newDefaultLibrary()->autorelease(); + MTL::Function* vertFunction = library->newFunction(NS::MakeConstantString("PreprocessAvatarVertexShader"))->autorelease(); MTL::Function* fragFunction = library->newFunction(NS::MakeConstantString("PreprocessAvatarFragmentShader"))->autorelease(); - + descriptor->setVertexFunction(vertFunction); descriptor->setFragmentFunction(fragFunction); - + MTL::VertexDescriptor* vertexDescriptor = MTL::VertexDescriptor::vertexDescriptor(); vertexDescriptor->attributes()->object(0)->setFormat(MTL::VertexFormatFloat2); vertexDescriptor->attributes()->object(0)->setBufferIndex(0); @@ -2883,16 +2826,16 @@ void plMetalPipeline::IPreprocessAvatarTextures() vertexDescriptor->attributes()->object(1)->setFormat(MTL::VertexFormatFloat2); vertexDescriptor->attributes()->object(1)->setBufferIndex(0); vertexDescriptor->attributes()->object(1)->setOffset(sizeof(float) * 2); - + vertexDescriptor->layouts()->object(0)->setStride(sizeof(float) * 4); - + descriptor->setVertexDescriptor(vertexDescriptor); - + descriptor->colorAttachments()->object(0)->setBlendingEnabled(false); descriptor->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatBGRA8Unorm); NS::Error* error = nullptr; baseAvatarRenderState = fDevice.fMetalDevice->newRenderPipelineState(descriptor, &error); - + descriptor->colorAttachments()->object(0)->setBlendingEnabled(true); descriptor->colorAttachments()->object(0)->setSourceRGBBlendFactor(MTL::BlendFactorSourceAlpha); descriptor->colorAttachments()->object(0)->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha); @@ -2903,40 +2846,38 @@ void plMetalPipeline::IPreprocessAvatarTextures() float uOff = 0.5f / rt->GetWidth(); float vOff = 0.5f / rt->GetHeight(); - - plClothingLayout *layout = plClothingMgr::GetClothingMgr()->GetLayout(co->fBase->fLayoutName); - for (plClothingItem *item : co->fItems) + plClothingLayout* layout = plClothingMgr::GetClothingMgr()->GetLayout(co->fBase->fLayoutName); + + for (plClothingItem* item : co->fItems) { - for (size_t j = 0; j < item->fElements.size(); j++) { for (int k = 0; k < plClothingElement::kLayerMax; k++) { if (item->fTextures[j][k] == nullptr) continue; - + itemBufferTex = item->fTextures[j][k]; hsColorRGBA tint = co->GetItemTint(item, k); if (k >= plClothingElement::kLayerSkinBlend1 && k <= plClothingElement::kLayerSkinLast) tint.a = co->fSkinBlends[k - plClothingElement::kLayerSkinBlend1]; - + if (k == plClothingElement::kLayerBase) { - if(fState.fCurrentPipelineState != baseAvatarRenderState) { + if (fState.fCurrentPipelineState != baseAvatarRenderState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(baseAvatarRenderState); fState.fCurrentPipelineState = baseAvatarRenderState; } - } - else + } else { - if(fState.fCurrentPipelineState != avatarRenderState) { + if (fState.fCurrentPipelineState != avatarRenderState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(avatarRenderState); fState.fCurrentPipelineState = avatarRenderState; } } fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&tint, sizeof(hsColorRGBA), 0); - + float screenW = (float)item->fElements[j]->fWidth / layout->fOrigWidth * 2.f; float screenH = (float)item->fElements[j]->fHeight / layout->fOrigWidth * 2.f; float screenX = (float)item->fElements[j]->fXPos / layout->fOrigWidth * 2.f - 1.f; @@ -2956,9 +2897,9 @@ void plMetalPipeline::IPreprocessAvatarTextures() } void plMetalPipeline::IDrawClothingQuad(float x, float y, float w, float h, - float uOff, float vOff, plMipmap *tex) + float uOff, float vOff, plMipmap* tex) { - const uint32_t kVSize = sizeof(plAVTexVert); + const uint32_t kVSize = sizeof(plAVTexVert); plMetalTextureRef* ref = (plMetalTextureRef*)tex->GetDeviceRef(); if (!ref || ref->IsDirty()) { @@ -2969,7 +2910,7 @@ void plMetalPipeline::IDrawClothingQuad(float x, float y, float w, float h, { IReloadTexture(tex, ref); } - hsRefCnt_SafeAssign( fLayerRef[0], ref ); + hsRefCnt_SafeAssign(fLayerRef[0], ref); fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(ref->fTexture, 0); plAVTexVert ptr[4]; @@ -2998,28 +2939,28 @@ void plMetalPipeline::IDrawClothingQuad(float x, float y, float w, float h, ptr[3] = vert; ptr[3].fPos[1] += h; ptr[3].fUv[1] -= 1.f; - + fDevice.CurrentRenderCommandEncoder()->setVertexBytes(ptr, sizeof(ptr), 0); fDevice.CurrentRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveType::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); } -void plMetalPipeline::FindFragFunction() { - MTL::Library *library = fDevice.fMetalDevice->newDefaultLibrary(); - - NS::Error *error = nullptr; - - MTL::FunctionConstantValues *functionContents = MTL::FunctionConstantValues::alloc()->init(); - short numUVs=1; +void plMetalPipeline::FindFragFunction() +{ + MTL::Library* library = fDevice.fMetalDevice->newDefaultLibrary(); + + NS::Error* error = nullptr; + + MTL::FunctionConstantValues* functionContents = MTL::FunctionConstantValues::alloc()->init(); + short numUVs = 1; functionContents->setConstantValue(&numUVs, MTL::DataTypeUShort, FunctionConstantNumUVs); functionContents->setConstantValue(&numUVs, MTL::DataTypeUShort, FunctionConstantNumLayers); - - MTL::Function *fragFunction = library->newFunction( - NS::String::string("pipelineFragmentShader", NS::ASCIIStringEncoding), - functionContents, - &error - ); + + MTL::Function* fragFunction = library->newFunction( + NS::String::string("pipelineFragmentShader", NS::ASCIIStringEncoding), + functionContents, + &error); fFragFunction = fragFunction; - + functionContents->release(); library->release(); } @@ -3035,7 +2976,7 @@ void plMetalPipeline::FindFragFunction() { void plMetalPipeline::IClearShadowSlaves() { int i; - for( i = 0; i < fShadows.size(); i++ ) + for (i = 0; i < fShadows.size(); i++) { const plShadowCaster* caster = fShadows[i]->fCaster; caster->GetKey()->UnRefObject(); @@ -3056,7 +2997,7 @@ bool plMetalPipeline::ICreateDynDeviceObjects() // Create device-specific stuff fDebugTextMgr = new plDebugTextManager(); - if( fDebugTextMgr == nil ) + if (fDebugTextMgr == nil) return true; // Vertex buffers, index buffers, textures, etc. @@ -3075,11 +3016,11 @@ void plMetalPipeline::IReleaseDynDeviceObjects() // themselves from their parent objects yet delete fDebugTextMgr; fDebugTextMgr = nil; - - while( fTextFontRefList ) + + while (fTextFontRefList) delete fTextFontRefList; - while( fRenderTargetRefList ) + while (fRenderTargetRefList) { plMetalRenderTargetRef* rtRef = fRenderTargetRefList; rtRef->Release(); @@ -3091,7 +3032,6 @@ void plMetalPipeline::IReleaseDynDeviceObjects() IReleaseDynamicBuffers(); //IReleaseAvRTPool(); IReleaseRenderTargetPools(); - } // IReleaseDynamicBuffers ///////////////////////////////////////////////// @@ -3111,42 +3051,42 @@ void plMetalPipeline::IReleaseRenderTargetPools() { int i; - for( i = 0; i < fRenderTargetPool512.size(); i++ ) + for (i = 0; i < fRenderTargetPool512.size(); i++) { delete fRenderTargetPool512[i]; fRenderTargetPool512[i] = nil; } fRenderTargetPool512.clear(); - for( i = 0; i < fRenderTargetPool256.size(); i++ ) + for (i = 0; i < fRenderTargetPool256.size(); i++) { delete fRenderTargetPool256[i]; fRenderTargetPool256[i] = nil; } fRenderTargetPool256.clear(); - for( i = 0; i < fRenderTargetPool128.size(); i++ ) + for (i = 0; i < fRenderTargetPool128.size(); i++) { delete fRenderTargetPool128[i]; fRenderTargetPool128[i] = nil; } fRenderTargetPool128.clear(); - for( i = 0; i < fRenderTargetPool64.size(); i++ ) + for (i = 0; i < fRenderTargetPool64.size(); i++) { delete fRenderTargetPool64[i]; fRenderTargetPool64[i] = nil; } fRenderTargetPool64.clear(); - for( i = 0; i < fRenderTargetPool32.size(); i++ ) + for (i = 0; i < fRenderTargetPool32.size(); i++) { delete fRenderTargetPool32[i]; fRenderTargetPool32[i] = nil; } fRenderTargetPool32.clear(); - for( i = 0; i < kMaxRenderTargetNext; i++ ) + for (i = 0; i < kMaxRenderTargetNext; i++) { fRenderTargetNext[i] = 0; //fBlurScratchRTs[i] = nil; @@ -3155,7 +3095,7 @@ void plMetalPipeline::IReleaseRenderTargetPools() #ifdef MF_ENABLE_HACKOFF hackOffscreens.Reset(); -#endif // MF_ENABLE_HACKOFF +#endif // MF_ENABLE_HACKOFF } /////////////////////////////////////////////////////////////////////////////// @@ -3164,10 +3104,8 @@ void plMetalPipeline::IReleaseRenderTargetPools() /////////////////////////////////////////////////////////////////////////////// // See plGLight/plShadowMaster.cpp for more notes. - - -float blurScale = -1.f; -static const int kL2NumSamples = 3; // Log2(4) +float blurScale = -1.f; +static const int kL2NumSamples = 3; // Log2(4) // IPrepShadowCaster //////////////////////////////////////////////////////////////////////// // Make sure all the geometry in this shadow caster is ready to be rendered. @@ -3189,9 +3127,9 @@ bool plMetalPipeline::IPrepShadowCaster(const plShadowCaster* caster) const std::vector& castSpans = caster->Spans(); int i; - for( i = 0; i < castSpans.size(); i++ ) + for (i = 0; i < castSpans.size(); i++) { - if( !done.IsBitSet(i) ) + if (!done.IsBitSet(i)) { // We haven't already done this castSpan @@ -3201,7 +3139,7 @@ bool plMetalPipeline::IPrepShadowCaster(const plShadowCaster* caster) static std::vector visList; visList.clear(); visList.push_back((int16_t)(castSpans[i].fIndex)); - + // We're about to have done this castSpan. done.SetBit(i); @@ -3209,9 +3147,9 @@ bool plMetalPipeline::IPrepShadowCaster(const plShadowCaster* caster) // with the same drawable, and add them to visList. // We'll handle all the spans from this drawable at once. int j; - for( j = i+1; j < castSpans.size(); j++ ) + for (j = i + 1; j < castSpans.size(); j++) { - if( !done.IsBitSet(j) && (castSpans[j].fDraw == drawable) ) + if (!done.IsBitSet(j) && (castSpans[j].fDraw == drawable)) { // Add to list visList.push_back((int16_t)(castSpans[j].fIndex)); @@ -3221,10 +3159,10 @@ bool plMetalPipeline::IPrepShadowCaster(const plShadowCaster* caster) } } // That's all, prep the drawable. - drawable->PrepForRender( this ); + drawable->PrepForRender(this); // Do any software skinning. - if( !ISoftwareVertexBlend(drawable, visList) ) + if (!ISoftwareVertexBlend(drawable, visList)) return false; } } @@ -3239,41 +3177,41 @@ bool plMetalPipeline::IRenderShadowCaster(plShadowSlave* slave) const plShadowCaster* caster = slave->fCaster; // Setup to render into the slave's render target. - if( !IPushShadowCastState(slave) ) + if (!IPushShadowCastState(slave)) return false; // Get the shadow caster ready to render. - if( !IPrepShadowCaster(slave->fCaster) ) + if (!IPrepShadowCaster(slave->fCaster)) return false; // for each shadowCaster.fSpans int iSpan; - for( iSpan = 0; iSpan < caster->Spans().size(); iSpan++ ) + for (iSpan = 0; iSpan < caster->Spans().size(); iSpan++) { plDrawableSpans* dr = caster->Spans()[iSpan].fDraw; - const plSpan* sp = caster->Spans()[iSpan].fSpan; - uint32_t spIdx = caster->Spans()[iSpan].fIndex; + const plSpan* sp = caster->Spans()[iSpan].fSpan; + uint32_t spIdx = caster->Spans()[iSpan].fIndex; hsAssert(sp->fTypeMask & plSpan::kIcicleSpan, "Shadow casting from non-trimeshes not currently supported"); // render shadowcaster.fSpans[i] to rendertarget - if( !(sp->fProps & plSpan::kPropNoShadowCast) ) + if (!(sp->fProps & plSpan::kPropNoShadowCast)) IRenderShadowCasterSpan(slave, dr, *(const plIcicle*)sp); // Keep track of which shadow slaves this span was rendered into. // If self-shadowing is off, we use that to determine not to // project the shadow map onto its source geometry. - sp->SetShadowBit(slave->fIndex); //index set in SubmitShadowSlave + sp->SetShadowBit(slave->fIndex); //index set in SubmitShadowSlave } // Debug only. - if( blurScale >= 0.f ) + if (blurScale >= 0.f) slave->fBlurScale = blurScale; // If this shadow requests being blurred, do it. - if( slave->fBlurScale > 0.f ) + if (slave->fBlurScale > 0.f) fDevice.EncodeBlur(fDevice.GetCurrentCommandBuffer(), fDevice.fCurrentFragmentOutputTexture, slave->fBlurScale); - + // Finished up, restore previous state. IPopShadowCastState(slave); @@ -3283,7 +3221,7 @@ bool plMetalPipeline::IRenderShadowCaster(plShadowSlave* slave) /// Add a span to our boundsIce to show this IAddBoundsSpan(fBoundsSpans, &slave->fWorldBounds); } -#endif // MCN_BOUNDS_SPANS +#endif // MCN_BOUNDS_SPANS return true; } @@ -3313,18 +3251,17 @@ void plMetalPipeline::IPreprocessShadows() // permutation explosion, because a slave is only generated // for a caster being affected (in range etc.) by a light. int iSlave; - for( iSlave = 0; iSlave < fShadows.size(); iSlave++ ) + for (iSlave = 0; iSlave < fShadows.size(); iSlave++) { plShadowSlave* slave = fShadows[iSlave]; - + // Any trouble, remove it from the list for this frame. - if( !IRenderShadowCaster(slave) ) + if (!IRenderShadowCaster(slave)) { fShadows.erase(fShadows.begin() + iSlave); iSlave--; continue; } - } // Restore @@ -3339,14 +3276,14 @@ void plMetalPipeline::IPreprocessShadows() bool plMetalPipeline::IPushShadowCastState(plShadowSlave* slave) { plRenderTarget* renderTarg = IFindRenderTarget(slave->fWidth, slave->fHeight, slave->fView.GetOrthogonal()); - if( !renderTarg ) + if (!renderTarg) return false; // Let the slave setup the transforms, viewport, etc. necessary to render it's shadow // map. This just goes into a plViewTransform, we translate that into D3D state ourselves below. if (!slave->SetupViewTransform(this)) return false; - + // Set texture to U_LUT fCurrentRenderPassUniforms->specularSrc = 0.0; @@ -3369,12 +3306,12 @@ bool plMetalPipeline::IPushShadowCastState(plShadowSlave* slave) // We'll be rendering the light space distance to the span fragment into // alpha (color is white), so our camera space position, transformed into light space // and then converted to [0..255] via our ULut. - + //METAL NOTE: D3DTSS_TCI_CAMERASPACEPOSITION and D3DTTFF_COUNT3 are hardcoded into the shader // Set texture transform to slave's lut transform. See plShadowMaster::IComputeLUT(). hsMatrix44 castLUT = slave->fCastLUT; - if( slave->fFlags & plShadowSlave::kCastInCameraSpace ) + if (slave->fFlags & plShadowSlave::kCastInCameraSpace) { hsMatrix44 c2w = GetCameraToWorld(); @@ -3441,26 +3378,25 @@ bool plMetalPipeline::IPushShadowCastState(plShadowSlave* slave) // Enable ZBuffering w/ write //fD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - // fLayerState[0].fZFlags &= ~hsGMatState::kZMask; + // fLayerState[0].fZFlags &= ~hsGMatState::kZMask; // Clear the render target: // alpha to white ensures no shadow where there's no caster // color to black in case we ever get blurring going // Z to 1 // Stencil ignored - if( slave->ReverseZ() ) + if (slave->ReverseZ()) { fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(fDevice.fReverseZStencilState); //fD3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL); //fD3DDevice->Clear(0, nil, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clearColor, 0.0f, 0L); - } - else + } else { fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(fDevice.fDefaultStencilState); } // Bring the viewport in (AFTER THE CLEAR) to protect the alpha boundary. - fView.GetViewTransform().SetViewPort(1, 1, (float)(slave->fWidth-2), (float)(slave->fHeight-2), false); + fView.GetViewTransform().SetViewPort(1, 1, (float)(slave->fWidth - 2), (float)(slave->fHeight - 2), false); fDevice.SetViewport(); //inlEnsureLightingOff(); @@ -3484,7 +3420,7 @@ void plMetalPipeline::ISetupShadowState(plShadowSlave* slave, plShadowState& sha slave->fSelfShadowOn = false; - if( slave->Positional() ) + if (slave->Positional()) { hsPoint3 position = slave->fLightPos; shadowState.lightPosition.x = position.fX; @@ -3492,19 +3428,17 @@ void plMetalPipeline::ISetupShadowState(plShadowSlave* slave, plShadowState& sha shadowState.lightPosition.z = position.fZ; shadowState.directional = false; - } - else + } else { hsVector3 dir = slave->fLightDir; shadowState.lightDirection.x = dir.fX; shadowState.lightDirection.y = dir.fY; shadowState.lightDirection.z = dir.fZ; - + shadowState.directional = true; } } - // IFindRenderTarget ////////////////////////////////////////////////////////////////// // Find a matching render target from the pools. We prefer the requested size, but // will look for a smaller size if there isn't one available. @@ -3513,38 +3447,38 @@ void plMetalPipeline::ISetupShadowState(plShadowSlave* slave, plShadowState& sha plRenderTarget* plMetalPipeline::IFindRenderTarget(uint32_t& width, uint32_t& height, bool ortho) { std::vector* pool = nil; - uint32_t* iNext = nil; + uint32_t* iNext = nil; // NOT CURRENTLY SUPPORTING NON-SQUARE SHADOWS. IF WE DO, CHANGE THIS. - switch(height) + switch (height) { - case 512: - pool = &fRenderTargetPool512; - iNext = &fRenderTargetNext[9]; - break; - case 256: - pool = &fRenderTargetPool256; - iNext = &fRenderTargetNext[8]; - break; - case 128: - pool = &fRenderTargetPool128; - iNext = &fRenderTargetNext[7]; - break; - case 64: - pool = &fRenderTargetPool64; - iNext = &fRenderTargetNext[6]; - break; - case 32: - pool = &fRenderTargetPool32; - iNext = &fRenderTargetNext[5]; - break; - default: - return nil; + case 512: + pool = &fRenderTargetPool512; + iNext = &fRenderTargetNext[9]; + break; + case 256: + pool = &fRenderTargetPool256; + iNext = &fRenderTargetNext[8]; + break; + case 128: + pool = &fRenderTargetPool128; + iNext = &fRenderTargetNext[7]; + break; + case 64: + pool = &fRenderTargetPool64; + iNext = &fRenderTargetNext[6]; + break; + case 32: + pool = &fRenderTargetPool32; + iNext = &fRenderTargetNext[5]; + break; + default: + return nil; } plRenderTarget* rt = (*pool)[*iNext]; - if( !rt ) + if (!rt) { // We didn't find one, try again the next size down. - if( height > 32 ) + if (height > 32) return IFindRenderTarget(width >>= 1, height >>= 1, ortho); // We must be totally out. Oh well. @@ -3562,21 +3496,21 @@ plRenderTarget* plMetalPipeline::IFindRenderTarget(uint32_t& width, uint32_t& he // that wants the depth buffer dimensions to match the color buffer size. // It may be that NVidia hardware doesn't care any more. Contact Matthias // about that. -hsGDeviceRef* plMetalPipeline::SharedRenderTargetRef(plRenderTarget* share, plRenderTarget *owner) +hsGDeviceRef* plMetalPipeline::SharedRenderTargetRef(plRenderTarget* share, plRenderTarget* owner) { - plMetalRenderTargetRef* ref = nil; - MTL::Texture* depthSurface = nil; - MTL::Texture* texture = nil; - MTL::Texture* cTexture = nil; + plMetalRenderTargetRef* ref = nil; + MTL::Texture* depthSurface = nil; + MTL::Texture* texture = nil; + MTL::Texture* cTexture = nil; int i; plCubicRenderTarget* cubicRT; - uint16_t width, height; + uint16_t width, height; // If we don't already have one to share from, start from scratch. - if( !share ) + if (!share) return MakeRenderTargetRef(owner); - //hsAssert(!fManagedAlloced, "Allocating non-managed resource with managed resources alloc'd"); + //hsAssert(!fManagedAlloced, "Allocating non-managed resource with managed resources alloc'd"); #ifdef HS_DEBUGGING // Check out the validity of the match. Debug only. @@ -3585,18 +3519,18 @@ hsGDeviceRef* plMetalPipeline::SharedRenderTargetRef(plRenderTarget* share, plRe hsAssert(owner->GetHeight() == share->GetHeight(), "Mismatch on shared render target"); hsAssert(owner->GetZDepth() == share->GetZDepth(), "Mismatch on shared render target"); hsAssert(owner->GetStencilDepth() == share->GetStencilDepth(), "Mismatch on shared render target"); -#endif // HS_DEBUGGING +#endif // HS_DEBUGGING /// Check--is this renderTarget really a child of a cubicRenderTarget? - if( owner->GetParent() != nil ) + if (owner->GetParent() != nil) { /// This'll create the deviceRefs for all of its children as well SharedRenderTargetRef(share->GetParent(), owner->GetParent()); return owner->GetDeviceRef(); } - if( owner->GetDeviceRef() != nil ) - ref = (plMetalRenderTargetRef *)owner->GetDeviceRef(); + if (owner->GetDeviceRef() != nil) + ref = (plMetalRenderTargetRef*)owner->GetDeviceRef(); // Look for a good format of matching color and depth size. //FIXME: we're hardcoded for a certain tier and we aren't trying to create matching render buffers for efficiency @@ -3606,7 +3540,6 @@ hsGDeviceRef* plMetalPipeline::SharedRenderTargetRef(plRenderTarget* share, plRe // return nil; //} - /// Create the render target now // Start with the depth. We're just going to share the depth surface on the // input shareRef. @@ -3617,116 +3550,111 @@ hsGDeviceRef* plMetalPipeline::SharedRenderTargetRef(plRenderTarget* share, plRe //FIXME: Add the usage to these textures, they're only accessed by the GPU // Check for Cubic. This is unlikely, since this function is currently only // used for the shadow map pools. - cubicRT = plCubicRenderTarget::ConvertNoRef( owner ); - if( cubicRT != nil ) + cubicRT = plCubicRenderTarget::ConvertNoRef(owner); + if (cubicRT != nil) { /// And create the ref (it'll know how to set all the flags) - if( ref != nil ) + if (ref != nil) ref->SetOwner(owner); else { ref = new plMetalRenderTargetRef(); ref->SetOwner(owner); } - + MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::textureCubeDescriptor(MTL::PixelFormatRGBA8Uint, owner->GetWidth(), false); - MTL::Texture* cubeTexture = fDevice.fMetalDevice->newTexture(textureDescriptor); + MTL::Texture* cubeTexture = fDevice.fMetalDevice->newTexture(textureDescriptor); - // hsAssert(!fManagedAlloced, "Alloc default with managed alloc'd"); - if( cubeTexture ) + // hsAssert(!fManagedAlloced, "Alloc default with managed alloc'd"); + if (cubeTexture) { - /// Create a CUBIC texture - for( i = 0; i < 6; i++ ) + for (i = 0; i < 6; i++) { - plRenderTarget *face = cubicRT->GetFace( i ); - plMetalRenderTargetRef *fRef; + plRenderTarget* face = cubicRT->GetFace(i); + plMetalRenderTargetRef* fRef; - if( face->GetDeviceRef() != nil ) + if (face->GetDeviceRef() != nil) { - fRef = (plMetalRenderTargetRef *)face->GetDeviceRef(); + fRef = (plMetalRenderTargetRef*)face->GetDeviceRef(); fRef->SetOwner(face); - if( !fRef->IsLinked() ) - fRef->Link( &fRenderTargetRefList ); - } - else + if (!fRef->IsLinked()) + fRef->Link(&fRenderTargetRefList); + } else { plMetalRenderTargetRef* targetRef = new plMetalRenderTargetRef(); targetRef->SetOwner(face); - face->SetDeviceRef( targetRef ); - ( (plMetalRenderTargetRef *)face->GetDeviceRef())->Link( &fRenderTargetRefList ); + face->SetDeviceRef(targetRef); + ((plMetalRenderTargetRef*)face->GetDeviceRef())->Link(&fRenderTargetRefList); // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) - hsRefCnt_SafeUnRef( face->GetDeviceRef() ); + hsRefCnt_SafeUnRef(face->GetDeviceRef()); } } ref->fTexture = cubeTexture; - } - else + } else { hsRefCnt_SafeUnRef(ref); ref = nil; } } // Is it a texture render target? Probably, since shadow maps are all we use this for. - else if( owner->GetFlags() & plRenderTarget::kIsTexture || owner->GetFlags() & plRenderTarget::kIsOffscreen) + else if (owner->GetFlags() & plRenderTarget::kIsTexture || owner->GetFlags() & plRenderTarget::kIsOffscreen) { //DX seperated the onscreen and offscreen types. Metal doesn't care. All render targets are textures. /// Create a normal texture - if( ref != nil ) + if (ref != nil) ref->SetOwner(owner); else { ref = new plMetalRenderTargetRef(); ref->SetOwner(owner); } - + MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatBGRA8Unorm, owner->GetWidth(), owner->GetHeight(), false); //Give compute shader write access textureDescriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite); MTL::Texture* texture = fDevice.fMetalDevice->newTexture(textureDescriptor); - if( texture ) + if (texture) { ref->fTexture = texture; - } - else + } else { hsRefCnt_SafeUnRef(ref); ref = nil; } - + if (owner->GetZDepth() && (owner->GetFlags() & (plRenderTarget::kIsTexture | plRenderTarget::kIsOffscreen))) { - MTL::TextureDescriptor *depthTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, + MTL::TextureDescriptor* depthTextureDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, owner->GetWidth(), owner->GetHeight(), false); - + if (fDevice.fMetalDevice->supportsFamily(MTL::GPUFamilyApple1)) { depthTextureDescriptor->setStorageMode(MTL::StorageModeMemoryless); - } else { + } else { depthTextureDescriptor->setStorageMode(MTL::StorageModePrivate); } depthTextureDescriptor->setUsage(MTL::TextureUsageRenderTarget); - MTL::Texture *depthBuffer = fDevice.fMetalDevice->newTexture(depthTextureDescriptor); + MTL::Texture* depthBuffer = fDevice.fMetalDevice->newTexture(depthTextureDescriptor); ref->fDepthBuffer = depthBuffer; } } - if( owner->GetDeviceRef() != ref ) + if (owner->GetDeviceRef() != ref) { - owner->SetDeviceRef( ref ); + owner->SetDeviceRef(ref); // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) - hsRefCnt_SafeUnRef( ref ); - if( ref != nil && !ref->IsLinked() ) - ref->Link( &fRenderTargetRefList ); - } - else + hsRefCnt_SafeUnRef(ref); + if (ref != nil && !ref->IsLinked()) + ref->Link(&fRenderTargetRefList); + } else { - if( ref != nil && !ref->IsLinked() ) - ref->Link( &fRenderTargetRefList ); + if (ref != nil && !ref->IsLinked()) + ref->Link(&fRenderTargetRefList); } - if( ref != nil ) + if (ref != nil) { - ref->SetDirty( false ); + ref->SetDirty(false); } return ref; @@ -3746,61 +3674,61 @@ void plMetalPipeline::IMakeRenderTargetPools() // These numbers were set with multi-player in mind, so should be reconsidered. // But do keep in mind that there are many things in production assets that cast // shadows besides the avatar. - plConst(float) kCount[kMaxRenderTargetNext] = { - 0, // 1x1 - 0, // 2x2 - 0, // 4x4 - 0, // 8x8 - 0, // 16x16 - 32, // 32x32 - 16, // 64x64 - 8, // 128x128 - 4, // 256x256 - 0 // 512x512 + plConst(float) kCount[kMaxRenderTargetNext] = { + 0, // 1x1 + 0, // 2x2 + 0, // 4x4 + 0, // 8x8 + 0, // 16x16 + 32, // 32x32 + 16, // 64x64 + 8, // 128x128 + 4, // 256x256 + 0 // 512x512 }; int i; - for( i = 0; i < kMaxRenderTargetNext; i++ ) + for (i = 0; i < kMaxRenderTargetNext; i++) { std::vector* pool = nil; - switch( i ) + switch (i) { - default: - case 0: - case 1: - case 2: - case 3: - case 4: - break; + default: + case 0: + case 1: + case 2: + case 3: + case 4: + break; - case 5: - pool = &fRenderTargetPool32; - break; - case 6: - pool = &fRenderTargetPool64; - break; - case 7: - pool = &fRenderTargetPool128; - break; - case 8: - pool = &fRenderTargetPool256; - break; - case 9: - pool = &fRenderTargetPool512; - break; + case 5: + pool = &fRenderTargetPool32; + break; + case 6: + pool = &fRenderTargetPool64; + break; + case 7: + pool = &fRenderTargetPool128; + break; + case 8: + pool = &fRenderTargetPool256; + break; + case 9: + pool = &fRenderTargetPool512; + break; } - if( pool ) + if (pool) { pool->resize(kCount[i] + 1); (*pool)[0] = nil; (*pool)[(int)(kCount[i])] = nil; int j; - for( j = 0; j < kCount[i]; j++ ) + for (j = 0; j < kCount[i]; j++) { uint16_t flags = plRenderTarget::kIsTexture | plRenderTarget::kIsProjected; - uint8_t bitDepth = 32; - uint8_t zDepth = 24; - uint8_t stencilDepth = 0; - + uint8_t bitDepth = 32; + uint8_t zDepth = 24; + uint8_t stencilDepth = 0; + // If we ever allow non-square shadows, change this. int width = 1 << i; int height = width; @@ -3810,10 +3738,10 @@ void plMetalPipeline::IMakeRenderTargetPools() // If we've failed to create our render target ref, we're probably out of // video memory. We'll return nil, and this guy just doesn't get a shadow // until more video memory turns up (not likely). - if( !SharedRenderTargetRef((*pool)[0], rt) ) + if (!SharedRenderTargetRef((*pool)[0], rt)) { delete rt; - pool->resize(j+1); + pool->resize(j + 1); (*pool)[j] = nil; break; } @@ -3833,7 +3761,7 @@ bool plMetalPipeline::IPopShadowCastState(plShadowSlave* slave) PopRenderTarget(); fView.fXformResetFlags = fView.kResetProjection | fView.kResetCamera; - + fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(nullptr, 16); return true; @@ -3846,7 +3774,7 @@ bool plMetalPipeline::IPopShadowCastState(plShadowSlave* slave) void plMetalPipeline::IResetRenderTargetPools() { int i; - for( i = 0; i < kMaxRenderTargetNext; i++ ) + for (i = 0; i < kMaxRenderTargetNext; i++) { fRenderTargetNext[i] = 0; //fBlurScratchRTs[i] = nil; @@ -3866,41 +3794,41 @@ void plMetalPipeline::IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSp ICheckDynBuffers(drawable, drawable->GetBufferGroup(span.fGroupIdx), &span); plProfile_EndTiming(CheckDyn); - plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef *)drawable->GetVertexRef(span.fGroupIdx, span.fVBufferIdx); - plMetalIndexBufferRef* iRef = (plMetalIndexBufferRef *)drawable->GetIndexRef(span.fGroupIdx, span.fIBufferIdx); + plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)drawable->GetVertexRef(span.fGroupIdx, span.fVBufferIdx); + plMetalIndexBufferRef* iRef = (plMetalIndexBufferRef*)drawable->GetIndexRef(span.fGroupIdx, span.fIBufferIdx); - if( vRef->GetBuffer() == nil || iRef->GetBuffer() == nil ) + if (vRef->GetBuffer() == nil || iRef->GetBuffer() == nil) { - hsAssert( false, "Trying to render a nil buffer pair!" ); + hsAssert(false, "Trying to render a nil buffer pair!"); return; } /// Switch to the vertex buffer we want plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalRenderShadowCasterPipelineState(&fDevice, vRef).GetRenderPipelineState(); - if(fState.fCurrentPipelineState != linkedPipeline->pipelineState) { + if (fState.fCurrentPipelineState != linkedPipeline->pipelineState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(linkedPipeline->pipelineState); fState.fCurrentPipelineState = linkedPipeline->pipelineState; } - + if (fState.fCurrentVertexBuffer != vRef->GetBuffer()) { fDevice.CurrentRenderCommandEncoder()->setVertexBuffer(vRef->GetBuffer(), 0, 0); fState.fCurrentVertexBuffer = vRef->GetBuffer(); } - + fState.fCurrentVertexBuffer = vRef->GetBuffer(); fDevice.fCurrentIndexBuffer = iRef->GetBuffer(); fState.fCurrentCullMode = MTL::CullModeNone; fDevice.CurrentRenderCommandEncoder()->setCullMode(MTL::CullModeNone); - uint32_t vStart = span.fVStartIdx; - uint32_t vLength = span.fVLength; - uint32_t iStart = span.fIPackedIdx; - uint32_t iLength= span.fILength; + uint32_t vStart = span.fVStartIdx; + uint32_t vLength = span.fVLength; + uint32_t iStart = span.fIPackedIdx; + uint32_t iLength = span.fILength; plRenderTriListFunc render(&fDevice, 0, vStart, vLength, iStart, iLength); static hsMatrix44 emptyMatrix; - hsMatrix44 m = emptyMatrix; + hsMatrix44 m = emptyMatrix; ISetupTransforms(drawable, span, m); @@ -3910,49 +3838,46 @@ void plMetalPipeline::IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSp render.RenderPrims(); } - // IRenderShadowsOntoSpan ///////////////////////////////////////////////////////////////////// // After doing the usual render for a span (all passes), we call the following. // If the span accepts shadows, this will loop over all the shadows active this // frame, and apply the ones that intersect this spans bounds. See below for details. -void plMetalPipeline::IRenderShadowsOntoSpan(const plRenderPrimFunc& render, const plSpan* span, hsGMaterial* mat, plMetalVertexBufferRef *vRef) +void plMetalPipeline::IRenderShadowsOntoSpan(const plRenderPrimFunc& render, const plSpan* span, hsGMaterial* mat, plMetalVertexBufferRef* vRef) { // We've already computed which shadows affect this span. That's recorded in slaveBits. const hsBitVector& slaveBits = span->GetShadowSlaves(); bool first = true; - for(size_t i = 0; i < fShadows.size(); i++ ) + for (size_t i = 0; i < fShadows.size(); i++) { - if( slaveBits.IsBitSet(fShadows[i]->fIndex) ) + if (slaveBits.IsBitSet(fShadows[i]->fIndex)) { // This slave affects this span. - if( first ) + if (first) { - // On the first, we do all the setup that is independent of // the shadow slave, so state that needs to get set once before // projecting any number of shadow maps. ISetupShadowRcvTextureStages(mat); first = false; - } // Now setup any state specific to this shadow slave. ISetupShadowSlaveTextures(fShadows[i]); - + // See ISetupShadowLight below for how the shadow light is used. // The shadow light isn't used in generating the shadow map, it's used // in projecting the shadow map onto the scene. plShadowState shadowState; ISetupShadowState(fShadows[i], shadowState); - + struct plMetalFragmentShaderDescription passDescription; memset(&passDescription, 0, sizeof(passDescription)); - + passDescription.numLayers = fCurrNumLayers = 3; - + /* Things get a wee bit complicated here. @@ -3966,20 +3891,20 @@ void plMetalPipeline::IRenderShadowsOntoSpan(const plRenderPrimFunc& render, con The shadow cast shader will automatically look in textures 0 and 1 when doing the third stage blend. This saves us a texture bind. */ - + passDescription.PopulateTextureInfo(mat->GetLayer(0), 0); passDescription.Populate(mat->GetLayer(0), 2); - - if (mat->GetNumLayers()>1) { + + if (mat->GetNumLayers() > 1) { passDescription.PopulateTextureInfo(mat->GetLayer(1), 1); passDescription.Populate(mat->GetLayer(1), 2); } //There's no texture for the third stage if we're reusing the textures //for the first and second stages from the last render. passDescription.passTypes[2] = PassTypeColor; - - plMetalDevice::plMetalLinkedPipeline *linkedPipeline = plMetalRenderShadowPipelineState(&fDevice, vRef, passDescription).GetRenderPipelineState(); - if(fState.fCurrentPipelineState != linkedPipeline->pipelineState) { + + plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalRenderShadowPipelineState(&fDevice, vRef, passDescription).GetRenderPipelineState(); + if (fState.fCurrentPipelineState != linkedPipeline->pipelineState) { fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(linkedPipeline->pipelineState); fState.fCurrentPipelineState = linkedPipeline->pipelineState; } @@ -3990,22 +3915,20 @@ void plMetalPipeline::IRenderShadowsOntoSpan(const plRenderPrimFunc& render, con // so we cache whether the shadow light is set for regular or // self shadowing intensity. If what we're doing now is different // than what we're currently set for, set it again. - if( selfShadowNow != fShadows[i]->fSelfShadowOn ) + if (selfShadowNow != fShadows[i]->fSelfShadowOn) { - // We lower the power on self shadowing, because the artists like to // crank up the shadow strength to huge values to get a darker shadow // on the environment, which causes the shadow on the avatar to get // way too dark. Another way to look at it is when self shadowing, // the surface being projected onto is going to be very close to // the surface casting the shadow (because they are the same object). - if( selfShadowNow ) + if (selfShadowNow) { plConst(float) kMaxSelfPower = 0.3f; - float power = (float) fShadows[i]->fPower > kMaxSelfPower ? (float) kMaxSelfPower : ((float) fShadows[i]->fPower); + float power = (float)fShadows[i]->fPower > kMaxSelfPower ? (float)kMaxSelfPower : ((float)fShadows[i]->fPower); shadowState.power = power; - } - else + } else { shadowState.power = fShadows[i]->fPower; } @@ -4018,15 +3941,12 @@ void plMetalPipeline::IRenderShadowsOntoSpan(const plRenderPrimFunc& render, con #ifndef PLASMA_EXTERNAL_RELEASE if (!IsDebugFlagSet(plPipeDbg::kFlagNoShadowApply)) -#endif // PLASMA_EXTERNAL_RELEASE +#endif // PLASMA_EXTERNAL_RELEASE render.RenderPrims(); - } } - } - // ISetupShadowRcvTextureStages //////////////////////////////////////////// // Set the generic stage states. We'll fill in the specific textures // for each slave later. @@ -4034,9 +3954,9 @@ void plMetalPipeline::ISetupShadowRcvTextureStages(hsGMaterial* mat) { //Do this first, this normally stomps all over our uniforms //FIXME: Way to encode layers without stomping all over uniforms? - plMetalMaterialShaderRef* matShader = (plMetalMaterialShaderRef *)mat->GetDeviceRef(); + plMetalMaterialShaderRef* matShader = (plMetalMaterialShaderRef*)mat->GetDeviceRef(); //matShader->encodeArguments(fDevice.CurrentRenderCommandEncoder(), fCurrentRenderPassUniforms, 0, 0, nullptr); - + // We're whacking about with renderstate independent of current material, // so make sure the next span processes it's material, even if it's the // same one. @@ -4046,46 +3966,39 @@ void plMetalPipeline::ISetupShadowRcvTextureStages(hsGMaterial* mat) ISetShadowLightState(mat); // Zbuffering on read-only - - - if(fState.fCurrentDepthStencilState != fDevice.fNoZWriteStencilState) { + + if (fState.fCurrentDepthStencilState != fDevice.fNoZWriteStencilState) { fDevice.CurrentRenderCommandEncoder()->setDepthStencilState(fDevice.fNoZWriteStencilState); fState.fCurrentDepthStencilState = fDevice.fNoZWriteStencilState; } - + int layerIndex = -1; // If mat's base layer is alpha'd, and we have > 3 TMU's factor // in the base layer's alpha. - if( (fMaxLayersAtOnce > 3) && mat->GetLayer(0)->GetTexture() && (mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendAlpha) ) + if ((fMaxLayersAtOnce > 3) && mat->GetLayer(0)->GetTexture() && (mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendAlpha)) { plLayerInterface* layer = mat->GetLayer(0); layerIndex = 0; - - // If the following conditions are met, it means that layer 1 is a better choice to // get the transparency from. The specific case we're looking for is vertex alpha // simulated by an invisible second layer alpha LUT (known as the alpha hack). - if( (layer->GetMiscFlags() & hsGMatState::kMiscBindNext) - && mat->GetLayer(1) - && !(mat->GetLayer(1)->GetMiscFlags() & hsGMatState::kMiscNoShadowAlpha) - && !(mat->GetLayer(1)->GetBlendFlags() & hsGMatState::kBlendNoTexAlpha) - && mat->GetLayer(1)->GetTexture() ) { - layer = mat->GetLayer(1); + if ((layer->GetMiscFlags() & hsGMatState::kMiscBindNext) && mat->GetLayer(1) && !(mat->GetLayer(1)->GetMiscFlags() & hsGMatState::kMiscNoShadowAlpha) && !(mat->GetLayer(1)->GetBlendFlags() & hsGMatState::kBlendNoTexAlpha) && mat->GetLayer(1)->GetTexture()) { + layer = mat->GetLayer(1); layerIndex = 1; } - + // Normal UVW source. uint32_t uvwSrc = layer->GetUVWSrc(); - - // Normal UVW source. + + // Normal UVW source. fCurrentRenderPassUniforms->uvTransforms[2].UVWSrc = uvwSrc; // MiscFlags to layer's misc flags matrix_float4x4 tXfm; hsMatrix2SIMD(layer->GetTransform(), &tXfm); fCurrentRenderPassUniforms->uvTransforms[2].transform = tXfm; } - + fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&layerIndex, sizeof(int), FragmentShaderArgumentShadowCastAlphaSrc); } @@ -4095,12 +4008,12 @@ void plMetalPipeline::ISetShadowLightState(hsGMaterial* mat) { fCurrLightingMethod = plSpan::kLiteShadow; - if( mat && mat->GetNumLayers() && mat->GetLayer(0) ) + if (mat && mat->GetNumLayers() && mat->GetLayer(0)) fCurrentRenderPassUniforms->diffuseCol.r = fCurrentRenderPassUniforms->diffuseCol.g = fCurrentRenderPassUniforms->diffuseCol.b = mat->GetLayer(0)->GetOpacity(); else fCurrentRenderPassUniforms->diffuseCol.r = fCurrentRenderPassUniforms->diffuseCol.g = fCurrentRenderPassUniforms->diffuseCol.b = 1.f; fCurrentRenderPassUniforms->diffuseCol.a = 1.f; - + fCurrentRenderPassUniforms->diffuseSrc = 1.0; fCurrentRenderPassUniforms->emissiveSrc = 1.0; fCurrentRenderPassUniforms->emissiveCol = 0.0; @@ -4116,7 +4029,7 @@ void plMetalPipeline::IDisableLightsForShadow() { //FIXME: Planned for removal - but used by projections. New light code will obsolete. int i; - for( i = 0; i < 8; i++ ) + for (i = 0; i < 8; i++) { IDisableLight(i); } @@ -4137,24 +4050,24 @@ void plMetalPipeline::ISetupShadowSlaveTextures(plShadowSlave* slave) // Set texture transform to slave's camera to texture transform plRenderTarget* renderTarg = (plRenderTarget*)slave->fPipeData; hsAssert(renderTarg, "Processing a slave that hasn't been rendered"); - if( !renderTarg ) + if (!renderTarg) return; plMetalTextureRef* ref = (plMetalTextureRef*)renderTarg->GetDeviceRef(); hsAssert(ref, "Shadow map ref should have been made when it was rendered"); - if( !ref ) + if (!ref) return; - hsRefCnt_SafeAssign( fLayerRef[0], ref ); + hsRefCnt_SafeAssign(fLayerRef[0], ref); fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(ref->fTexture, 16); plMetalShadowCastFragmentShaderArgumentBuffer uniforms; uniforms.pointLightCast = slave->fView.GetOrthogonal() ? false : true; fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&uniforms, sizeof(plMetalShadowCastFragmentShaderArgumentBuffer), FragmentShaderArgumentShadowCastUniforms); - - hsMatrix44 cameraToTexture = slave->fWorldToTexture * c2w; + + hsMatrix44 cameraToTexture = slave->fWorldToTexture * c2w; simd_float4x4 tXfm; hsMatrix2SIMD(cameraToTexture, &tXfm); - + fCurrentRenderPassUniforms->uvTransforms[0].UVWSrc = plLayerInterface::kUVWPosition; fCurrentRenderPassUniforms->uvTransforms[0].transform = tXfm; @@ -4162,10 +4075,9 @@ void plMetalPipeline::ISetupShadowSlaveTextures(plShadowSlave* slave) // Set the texture transform to slave's fRcvLUT hsMatrix44 cameraToLut = slave->fRcvLUT * c2w; hsMatrix2SIMD(cameraToLut, &tXfm); - + fCurrentRenderPassUniforms->uvTransforms[1].UVWSrc = plLayerInterface::kUVWPosition; fCurrentRenderPassUniforms->uvTransforms[1].transform = tXfm; - } /////////////////////////////////////////////////////////////////////////////// @@ -4178,7 +4090,7 @@ void plMetalPipeline::ISetupShadowSlaveTextures(plShadowSlave* slave) bool plMetalPipeline::IIsViewLeftHanded() { - return fView.GetViewTransform().GetOrthogonal() ^ ( fView.fLocalToWorldLeftHanded ^ fView.fWorldToCamLeftHanded ) ? true : false; + return fView.GetViewTransform().GetOrthogonal() ^ (fView.fLocalToWorldLeftHanded ^ fView.fWorldToCamLeftHanded) ? true : false; } //// ISetCullMode ///////////////////////////////////////////////////////////// @@ -4203,7 +4115,7 @@ plMetalDevice* plMetalPipeline::GetMetalDevice() //FIXME: CPU avatar stuff that should be evaluated once this moves onto the GPU. -template +template static inline void inlCopy(uint8_t*& src, uint8_t*& dst) { T* src_ptr = reinterpret_cast(src); @@ -4213,7 +4125,7 @@ static inline void inlCopy(uint8_t*& src, uint8_t*& dst) dst += sizeof(T); } -template +template static inline const uint8_t* inlExtract(const uint8_t* src, T* val) { const T* ptr = reinterpret_cast(src); @@ -4221,11 +4133,11 @@ static inline const uint8_t* inlExtract(const uint8_t* src, T* val) return reinterpret_cast(ptr); } -template<> +template <> inline const uint8_t* inlExtract(const uint8_t* src, hsPoint3* val) { const float* src_ptr = reinterpret_cast(src); - float* dst_ptr = reinterpret_cast(val); + float* dst_ptr = reinterpret_cast(val); *dst_ptr++ = *src_ptr++; *dst_ptr++ = *src_ptr++; *dst_ptr++ = *src_ptr++; @@ -4233,11 +4145,11 @@ inline const uint8_t* inlExtract(const uint8_t* src, hsPoint3* val) return reinterpret_cast(src_ptr); } -template<> +template <> inline const uint8_t* inlExtract(const uint8_t* src, hsVector3* val) { const float* src_ptr = reinterpret_cast(src); - float* dst_ptr = reinterpret_cast(val); + float* dst_ptr = reinterpret_cast(val); *dst_ptr++ = *src_ptr++; *dst_ptr++ = *src_ptr++; *dst_ptr++ = *src_ptr++; @@ -4245,13 +4157,13 @@ inline const uint8_t* inlExtract(const uint8_t* src, hsVector3* val) return reinterpret_cast(src_ptr); } -template +template static inline void inlSkip(uint8_t*& src) { src += sizeof(T) * N; } -template +template static inline uint8_t* inlStuff(uint8_t* dst, const T* val) { T* ptr = reinterpret_cast(dst); @@ -4287,18 +4199,18 @@ bool plMetalPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std: // lock the data buffer // First, figure out which buffers we need to blend. - const int kMaxBufferGroups = 20; - const int kMaxVertexBuffers = 20; + const int kMaxBufferGroups = 20; + const int kMaxVertexBuffers = 20; static char blendBuffers[kMaxBufferGroups][kMaxVertexBuffers]; memset(blendBuffers, 0, kMaxBufferGroups * kMaxVertexBuffers * sizeof(**blendBuffers)); hsAssert(kMaxBufferGroups >= drawable->GetNumBufferGroups(), "Bigger than we counted on num groups skin."); const std::vector& spans = drawable->GetSpanArray(); - int i; + int i; for (i = 0; i < visList.size(); i++) { if (blendBits.IsBitSet(visList[i])) { - const plVertexSpan &vSpan = *(plVertexSpan *)spans[visList[i]]; + const plVertexSpan& vSpan = *(plVertexSpan*)spans[visList[i]]; hsAssert(kMaxVertexBuffers > vSpan.fVBufferIdx, "Bigger than we counted on num buffers skin."); blendBuffers[vSpan.fGroupIdx][vSpan.fVBufferIdx] = 1; @@ -4311,11 +4223,11 @@ bool plMetalPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std: // uses it, set the matrix palette and and then do the blend for that span. // When we've done all the spans for a group/buffer, we unlock it and move on. int j; - for( i = 0; i < kMaxBufferGroups; i++ ) + for (i = 0; i < kMaxBufferGroups; i++) { - for( j = 0; j < kMaxVertexBuffers; j++ ) + for (j = 0; j < kMaxVertexBuffers; j++) { - if( blendBuffers[i][j] ) + if (blendBuffers[i][j]) { // Found one. Do the lock. plMetalVertexBufferRef* vRef = (plMetalVertexBufferRef*)drawable->GetVertexRef(i, j); @@ -4335,15 +4247,15 @@ bool plMetalPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std: uint8_t* ptr = vRef->fOwner->GetVertBufferData(vRef->fIndex); ptr += span.fVStartIdx * vRef->fOwner->GetVertexSize(); - IBlendVertBuffer( (plSpan*)&span, - matrixPalette, span.fNumMatrices, - ptr, - vRef->fOwner->GetVertexFormat(), - vRef->fOwner->GetVertexSize(), - destPtr + span.fVStartIdx * vRef->fVertexSize, - vRef->fVertexSize, - span.fVLength, - span.fLocalUVWChans ); + IBlendVertBuffer((plSpan*)&span, + matrixPalette, span.fNumMatrices, + ptr, + vRef->fOwner->GetVertexFormat(), + vRef->fOwner->GetVertexSize(), + destPtr + span.fVStartIdx * vRef->fVertexSize, + vRef->fVertexSize, + span.fVLength, + span.fLocalUVWChans); vRef->SetDirty(true); } } @@ -4363,29 +4275,28 @@ bool plMetalPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std: return true; } - //// IBlendVertsIntoBuffer //////////////////////////////////////////////////// // Given a pointer into a buffer of verts that have blending data in the D3D // format, blends them into the destination buffer given without the blending // info. void plMetalPipeline::IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, int numMatrices, - const uint8_t* src, uint8_t format, uint32_t srcStride, - uint8_t* dest, uint32_t destStride, uint32_t count, - uint16_t localUVWChans) + const uint8_t* src, uint8_t format, uint32_t srcStride, + uint8_t* dest, uint32_t destStride, uint32_t count, + uint16_t localUVWChans) { - float pt_buf[] = { 0.f, 0.f, 0.f, 1.f }; - float vec_buf[] = { 0.f, 0.f, 0.f, 0.f }; - hsPoint3* pt = reinterpret_cast(pt_buf); - hsVector3* vec = reinterpret_cast(vec_buf); + float pt_buf[] = {0.f, 0.f, 0.f, 1.f}; + float vec_buf[] = {0.f, 0.f, 0.f, 0.f}; + hsPoint3* pt = reinterpret_cast(pt_buf); + hsVector3* vec = reinterpret_cast(vec_buf); - uint32_t indices; - float weights[4]; + uint32_t indices; + float weights[4]; // Dropped support for localUVWChans at templatization of code hsAssert(localUVWChans == 0, "support for skinned UVWs dropped. reimplement me?"); const size_t uvChanSize = plGBufferGroup::CalcNumUVs(format) * sizeof(float) * 3; - uint8_t numWeights = (format & plGBufferGroup::kSkinWeightMask) >> 4; + uint8_t numWeights = (format & plGBufferGroup::kSkinWeightMask) >> 4; for (uint32_t i = 0; i < count; ++i) { // Extract data @@ -4405,20 +4316,20 @@ void plMetalPipeline::IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, src = inlExtract(src, vec); // Destination buffers (float4 for SSE alignment) - simd_float4 destNorm_buf = (simd_float4){ 0.f, 0.f, 0.f, 0.f }; - simd_float4 destPt_buf = (simd_float4){ 0.f, 0.f, 0.f, 1.f }; + simd_float4 destNorm_buf = (simd_float4){0.f, 0.f, 0.f, 0.f}; + simd_float4 destPt_buf = (simd_float4){0.f, 0.f, 0.f, 1.f}; simd_float4x4 simdMatrix; - + // Blend for (uint32_t j = 0; j < numWeights + 1; ++j) { hsMatrix2SIMD(matrixPalette[indices & 0xFF], &simdMatrix); if (weights[j]) { //Note: This bit is different than GL/DirectX. It's using acclerate so this is also accelerated on ARM through NEON or maybe even the Neural Engine. - destPt_buf += simd_mul(*(simd_float4 *)pt_buf, simdMatrix) * weights[j]; - destNorm_buf += simd_mul(*(simd_float4 *)vec_buf, simdMatrix) * weights[j]; + destPt_buf += simd_mul(*(simd_float4*)pt_buf, simdMatrix) * weights[j]; + destNorm_buf += simd_mul(*(simd_float4*)vec_buf, simdMatrix) * weights[j]; } - //ISkinVertexSSE41(matrixPalette[indices & 0xFF], weights[j], pt_buf, destPt_buf, vec_buf, destNorm_buf); + //ISkinVertexSSE41(matrixPalette[indices & 0xFF], weights[j], pt_buf, destPt_buf, vec_buf, destNorm_buf); indices >>= 8; } // Probably don't really need to renormalize this. There errors are @@ -4431,7 +4342,7 @@ void plMetalPipeline::IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, // Jump past colors and UVws dest += sizeof(uint32_t) * 2 + uvChanSize; - src += sizeof(uint32_t) * 2 + uvChanSize; + src += sizeof(uint32_t) * 2 + uvChanSize; } } @@ -4451,18 +4362,18 @@ void plMetalPipeline::CheckTextureRef(plLayerInterface* layer) void plMetalPipeline::CheckTextureRef(plBitmap* bitmap) { plMetalTextureRef* tRef = static_cast(bitmap->GetDeviceRef()); - + if (!tRef) { tRef = static_cast(MakeTextureRef(bitmap)); } - + // If it's dirty, refill it. if (tRef->IsDirty()) { IReloadTexture(bitmap, tRef); } } -hsGDeviceRef *plMetalPipeline::MakeTextureRef(plBitmap* bitmap) +hsGDeviceRef* plMetalPipeline::MakeTextureRef(plBitmap* bitmap) { plMetalTextureRef* tRef = static_cast(bitmap->GetDeviceRef()); @@ -4481,12 +4392,12 @@ hsGDeviceRef *plMetalPipeline::MakeTextureRef(plBitmap* bitmap) // If it's dirty, refill it. if (tRef->IsDirty()) { - IReloadTexture( bitmap, tRef ); + IReloadTexture(bitmap, tRef); } return tRef; } -void plMetalPipeline::IReloadTexture( plBitmap* bitmap, plMetalTextureRef *ref ) +void plMetalPipeline::IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref) { plMipmap* mip = plMipmap::ConvertNoRef(bitmap); if (mip) { @@ -4532,8 +4443,7 @@ void plMetalPipeline::CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) // Might want to remove this assert, and replace it with a dirty check // if we have static buffers that change very seldom rather than never. hsAssert(!vRef->IsDirty(), "Non-volatile vertex buffers should never get dirty"); - } - else + } else { // Make sure we're going to be ready to fill it. if (!vRef->fData && (vRef->fFormat != owner->GetVertexFormat())) @@ -4572,12 +4482,11 @@ void plMetalPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) //// IGetBufferFormatSize ///////////////////////////////////////////////////// // Calculate the vertex stride from the given format. -uint32_t plMetalPipeline::IGetBufferFormatSize( uint8_t format ) const +uint32_t plMetalPipeline::IGetBufferFormatSize(uint8_t format) const { - uint32_t size = sizeof( float ) * 6 + sizeof( uint32_t ) * 2; // Position and normal, and two packed colors + uint32_t size = sizeof(float) * 6 + sizeof(uint32_t) * 2; // Position and normal, and two packed colors - - switch( format & plGBufferGroup::kSkinWeightMask ) + switch (format & plGBufferGroup::kSkinWeightMask) { case plGBufferGroup::kSkinNoWeights: break; @@ -4585,10 +4494,10 @@ uint32_t plMetalPipeline::IGetBufferFormatSize( uint8_t format ) const size += sizeof(float); break; default: - hsAssert( false, "Invalid skin weight value in IGetBufferFormatSize()" ); + hsAssert(false, "Invalid skin weight value in IGetBufferFormatSize()"); } - size += sizeof( float ) * 3 * plGBufferGroup::CalcNumUVs( format ); + size += sizeof(float) * 3 * plGBufferGroup::CalcNumUVs(format); return size; } @@ -4599,8 +4508,8 @@ void plMetalPipeline::plMetalPipelineCurrentState::Reset() fCurrentDepthStencilState = nullptr; fCurrentVertexBuffer = nullptr; fCurrentCullMode.reset(); - - for(auto& layer: layerStates) + + for (auto& layer : layerStates) { layer.clampFlag = hsGMatState::hsGMatClampFlags(-1); } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 27ee222bad..e80f4da065 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -42,15 +42,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef _plMetalPipeline_inc_ #define _plMetalPipeline_inc_ -#include "plPipeline/pl3DPipeline.h" -#include "plPipeline/hsG3DDeviceSelector.h" -#include "plMetalDevice.h" -#include #include -#include "ShaderTypes.h" - +#include #include +#include "ShaderTypes.h" +#include "plMetalDevice.h" +#include "plPipeline/hsG3DDeviceSelector.h" +#include "plPipeline/pl3DPipeline.h" + class plIcicle; class plPlate; class plMetalMaterialShaderRef; @@ -63,12 +63,13 @@ const uint kMaxSkinWeightsPerMaterial = 3; class plMetalEnumerate { -public: - plMetalEnumerate() { + public: + plMetalEnumerate() + { hsG3DDeviceSelector::AddDeviceEnumerator(&plMetalEnumerate::Enumerate); } -private: + private: static void Enumerate(std::vector& records); }; @@ -79,101 +80,99 @@ class plMetalEnumerate // of duplicating everything because the one line to render is different. class plRenderPrimFunc { -public: - virtual bool RenderPrims() const = 0; // return true on error + public: + virtual bool RenderPrims() const = 0; // return true on error }; class plMetalPipeline : public pl3DPipeline { -public: - //The actual client should set this callback so we can retrieve drawables from the window server - std::function currentDrawableCallback; + public: + //The actual client should set this callback so we can retrieve drawables from the window server + std::function currentDrawableCallback; //caching the frag function here so that the shader compiler can quickly access it - MTL::Function* fFragFunction; - -protected: + MTL::Function* fFragFunction; + protected: friend class plMetalDevice; friend class plMetalPlateManager; friend class plMetalMaterialShaderRef; friend class plRenderTriListFunc; friend class plMetalTextFont; - plMetalMaterialShaderRef* fMatRefList; - plMetalRenderTargetRef* fRenderTargetRefList; - -public: - plMetalPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode); + plMetalMaterialShaderRef* fMatRefList; + plMetalRenderTargetRef* fRenderTargetRefList; + + public: + plMetalPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord* devMode); virtual ~plMetalPipeline(); - + CLASSNAME_REGISTER(plMetalPipeline); GETINTERFACE_ANY(plMetalPipeline, plPipeline); - + /* All of these virtual methods are not implemented by pl3DPipeline and * need to be re-implemented here! */ /*** VIRTUAL METHODS ***/ - bool PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr=nullptr) override; - bool PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr=nullptr) override; - plTextFont* MakeTextFont(ST::string face, uint16_t size) override; - bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) override; - bool CloseAccess(plAccessSpan& acc) override; - void PushRenderRequest(plRenderRequest* req) override; - void PopRenderRequest(plRenderRequest* req) override; - void ClearRenderTarget(plDrawable* d) override; - void ClearRenderTarget(const hsColorRGBA* col = nullptr, const float* depth = nullptr) override; - hsGDeviceRef* MakeRenderTargetRef(plRenderTarget* owner) override; - bool BeginRender() override; - bool EndRender() override; - void RenderScreenElements() override; - bool IsFullScreen() const override; - void Resize(uint32_t width, uint32_t height) override; - void LoadResources() override; - bool SetGamma(float eR, float eG, float eB) override; - bool SetGamma(const uint16_t* const tabR, const uint16_t* const tabG, const uint16_t* const tabB) override; - bool SetGamma10(const uint16_t *const tabR, const uint16_t *const tabG, const uint16_t *const tabB) override; - bool Supports10BitGamma() const override { return true; }; - bool CaptureScreen(plMipmap* dest, bool flipVertical = false, uint16_t desiredWidth = 0, uint16_t desiredHeight = 0) override; - plMipmap* ExtractMipMap(plRenderTarget* targ) override; - void GetSupportedDisplayModes(std::vector *res, int ColorDepth = 32 ) override; - int GetMaxAnisotropicSamples() override; - int GetMaxAntiAlias(int Width, int Height, int ColorDepth) override; - void ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool vSync = false) override; - void RenderSpans(plDrawableSpans* ice, const std::vector& visList) override; - void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); - bool ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup* group, const plSpan* spanBase); - bool IRefreshDynVertices(plGBufferGroup* group, plMetalVertexBufferRef* vRef); - void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, - hsGDeviceRef* ib, hsGMaterial* material, - uint32_t vStart, uint32_t vLength, - uint32_t iStart, uint32_t iLength); - void IRenderAuxSpan(const plSpan& span, const plAuxSpan* aux); - void IRenderAuxSpans(const plSpan& span); - bool IHandleMaterialPass(hsGMaterial *material, uint32_t pass, const plSpan *currSpan, const plMetalVertexBufferRef* vRef, const bool allowShaders = true); + bool PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr = nullptr) override; + bool PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr = nullptr) override; + plTextFont* MakeTextFont(ST::string face, uint16_t size) override; + bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) override; + bool CloseAccess(plAccessSpan& acc) override; + void PushRenderRequest(plRenderRequest* req) override; + void PopRenderRequest(plRenderRequest* req) override; + void ClearRenderTarget(plDrawable* d) override; + void ClearRenderTarget(const hsColorRGBA* col = nullptr, const float* depth = nullptr) override; + hsGDeviceRef* MakeRenderTargetRef(plRenderTarget* owner) override; + bool BeginRender() override; + bool EndRender() override; + void RenderScreenElements() override; + bool IsFullScreen() const override; + void Resize(uint32_t width, uint32_t height) override; + void LoadResources() override; + bool SetGamma(float eR, float eG, float eB) override; + bool SetGamma(const uint16_t* const tabR, const uint16_t* const tabG, const uint16_t* const tabB) override; + bool SetGamma10(const uint16_t* const tabR, const uint16_t* const tabG, const uint16_t* const tabB) override; + bool Supports10BitGamma() const override { return true; }; + bool CaptureScreen(plMipmap* dest, bool flipVertical = false, uint16_t desiredWidth = 0, uint16_t desiredHeight = 0) override; + plMipmap* ExtractMipMap(plRenderTarget* targ) override; + void GetSupportedDisplayModes(std::vector* res, int ColorDepth = 32) override; + int GetMaxAnisotropicSamples() override; + int GetMaxAntiAlias(int Width, int Height, int ColorDepth) override; + void ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool vSync = false) override; + void RenderSpans(plDrawableSpans* ice, const std::vector& visList) override; + void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); + bool ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup* group, const plSpan* spanBase); + bool IRefreshDynVertices(plGBufferGroup* group, plMetalVertexBufferRef* vRef); + void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, + hsGDeviceRef* ib, hsGMaterial* material, + uint32_t vStart, uint32_t vLength, + uint32_t iStart, uint32_t iLength); + void IRenderAuxSpan(const plSpan& span, const plAuxSpan* aux); + void IRenderAuxSpans(const plSpan& span); + bool IHandleMaterialPass(hsGMaterial* material, uint32_t pass, const plSpan* currSpan, const plMetalVertexBufferRef* vRef, const bool allowShaders = true); plMetalDevice* GetMetalDevice(); - + // Create and/or Refresh geometry buffers - void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; - void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; - void CheckTextureRef(plLayerInterface* lay) override; - void CheckTextureRef(plBitmap* bitmap); - hsGDeviceRef *MakeTextureRef(plBitmap* bitmap); - void IReloadTexture( plBitmap* bitmap, plMetalTextureRef *ref ); - - uint32_t IGetBufferFormatSize( uint8_t format ) const; - + void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; + void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; + void CheckTextureRef(plLayerInterface* lay) override; + void CheckTextureRef(plBitmap* bitmap); + hsGDeviceRef* MakeTextureRef(plBitmap* bitmap); + void IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref); + + uint32_t IGetBufferFormatSize(uint8_t format) const; + plRenderTarget* PopRenderTarget() override; - - MTL::PixelFormat GetFramebufferFormat() { return fDevice.GetFramebufferFormat(); }; - void SetFramebufferFormat(MTL::PixelFormat format) { fDevice.SetFramebufferFormat(format); }; - -private: - - VertexUniforms* fCurrentRenderPassUniforms; - + + MTL::PixelFormat GetFramebufferFormat() { return fDevice.GetFramebufferFormat(); }; + void SetFramebufferFormat(MTL::PixelFormat format) { fDevice.SetFramebufferFormat(format); }; + + private: + VertexUniforms* fCurrentRenderPassUniforms; + void FindFragFunction(); - + void ISelectLights(const plSpan* span, plMetalMaterialShaderRef* mRef, bool proj = false); void IEnableLight(size_t i, plLightInfo* light); void IDisableLight(size_t i); @@ -181,112 +180,116 @@ class plMetalPipeline : public pl3DPipeline void ICalcLighting(plMetalMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan); void IHandleBlendMode(hsGMatState flags); void IHandleZMode(hsGMatState flags); - + void IDrawPlate(plPlate* plate); void IPreprocessAvatarTextures(); void IDrawClothingQuad(float x, float y, float w, float h, - float uOff, float vOff, plMipmap *tex); + float uOff, float vOff, plMipmap* tex); void IClearShadowSlaves(); - + void ICreateDeviceObjects(); void IReleaseDynDeviceObjects(); bool ICreateDynDeviceObjects(); void IReleaseDynamicBuffers(); void IReleaseDeviceObjects(); - + bool IIsViewLeftHanded(); void ISetCullMode(bool flip = false); - + plLayerInterface* IPushOverBaseLayer(plLayerInterface* li); plLayerInterface* IPopOverBaseLayer(plLayerInterface* li); plLayerInterface* IPushOverAllLayer(plLayerInterface* li); plLayerInterface* IPopOverAllLayer(plLayerInterface* li); - - void IPushPiggyBacks(hsGMaterial* mat); - void IPopPiggyBacks(); - void IPushProjPiggyBack(plLayerInterface* li); - void IPopProjPiggyBacks(); + + void IPushPiggyBacks(hsGMaterial* mat); + void IPopPiggyBacks(); + void IPushProjPiggyBack(plLayerInterface* li); + void IPopProjPiggyBacks(); size_t ISetNumActivePiggyBacks(); - bool ICheckAuxBuffers(const plAuxSpan* span); - + bool ICheckAuxBuffers(const plAuxSpan* span); + void ISetPipeConsts(plShader* shader); - bool ISetShaders(const plMetalVertexBufferRef * vRef, const hsGMatState blendMode, plShader* vShader, plShader* pShader); - + bool ISetShaders(const plMetalVertexBufferRef* vRef, const hsGMatState blendMode, plShader* vShader, plShader* pShader); + bool ISoftwareVertexBlend(plDrawableSpans* drawable, const std::vector& visList); void IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, int numMatrices, - const uint8_t* src, uint8_t format, uint32_t srcStride, - uint8_t* dest, uint32_t destStride, uint32_t count, - uint16_t localUVWChans); - - plMetalVertexShader* fVShaderRefList; - plMetalFragmentShader* fPShaderRefList; - bool IPrepShadowCaster(const plShadowCaster* caster); - bool IRenderShadowCaster(plShadowSlave* slave); - void IPreprocessShadows(); - bool IPushShadowCastState(plShadowSlave* slave); - plRenderTarget* IFindRenderTarget(uint32_t& width, uint32_t& height, bool ortho); - bool IPopShadowCastState(plShadowSlave* slave); - void IResetRenderTargetPools(); - void IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSpans* drawable, const plIcicle& span); - plMetalTextureRef* fULutTextureRef; - void IMakeRenderTargetPools(); - hsGDeviceRef* SharedRenderTargetRef(plRenderTarget* share, plRenderTarget *owner); - void IRenderShadowsOntoSpan(const plRenderPrimFunc& render, const plSpan* span, hsGMaterial* mat, plMetalVertexBufferRef *vRef); - void ISetupShadowRcvTextureStages(hsGMaterial* mat); - void ISetupShadowSlaveTextures(plShadowSlave* slave); - void ISetShadowLightState(hsGMaterial* mat); - void ISetupShadowState(plShadowSlave* slave, plShadowState& shadowState); - void IDisableLightsForShadow(); - void IReleaseRenderTargetPools(); - void IRenderProjectionEach(const plRenderPrimFunc& render, hsGMaterial* material, int iPass, const plSpan& span, const plMetalVertexBufferRef* vRef); - void IRenderProjections(const plRenderPrimFunc& render, const plMetalVertexBufferRef* vRef); - void IRenderProjection(const plRenderPrimFunc& render, plLightInfo* li, const plMetalVertexBufferRef* vRef); - - void ISetLayer( uint32_t lay ); - + const uint8_t* src, uint8_t format, uint32_t srcStride, + uint8_t* dest, uint32_t destStride, uint32_t count, + uint16_t localUVWChans); + + plMetalVertexShader* fVShaderRefList; + plMetalFragmentShader* fPShaderRefList; + bool IPrepShadowCaster(const plShadowCaster* caster); + bool IRenderShadowCaster(plShadowSlave* slave); + void IPreprocessShadows(); + bool IPushShadowCastState(plShadowSlave* slave); + plRenderTarget* IFindRenderTarget(uint32_t& width, uint32_t& height, bool ortho); + bool IPopShadowCastState(plShadowSlave* slave); + void IResetRenderTargetPools(); + void IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSpans* drawable, const plIcicle& span); + plMetalTextureRef* fULutTextureRef; + void IMakeRenderTargetPools(); + hsGDeviceRef* SharedRenderTargetRef(plRenderTarget* share, plRenderTarget* owner); + void IRenderShadowsOntoSpan(const plRenderPrimFunc& render, const plSpan* span, hsGMaterial* mat, plMetalVertexBufferRef* vRef); + void ISetupShadowRcvTextureStages(hsGMaterial* mat); + void ISetupShadowSlaveTextures(plShadowSlave* slave); + void ISetShadowLightState(hsGMaterial* mat); + void ISetupShadowState(plShadowSlave* slave, plShadowState& shadowState); + void IDisableLightsForShadow(); + void IReleaseRenderTargetPools(); + void IRenderProjectionEach(const plRenderPrimFunc& render, hsGMaterial* material, int iPass, const plSpan& span, const plMetalVertexBufferRef* vRef); + void IRenderProjections(const plRenderPrimFunc& render, const plMetalVertexBufferRef* vRef); + void IRenderProjection(const plRenderPrimFunc& render, plLightInfo* li, const plMetalVertexBufferRef* vRef); + + void ISetLayer(uint32_t lay); + // Shadows - std::vector fRenderTargetPool512; - std::vector fRenderTargetPool256; - std::vector fRenderTargetPool128; - std::vector fRenderTargetPool64; - std::vector fRenderTargetPool32; - enum { kMaxRenderTargetNext = 10 }; - uint32_t fRenderTargetNext[kMaxRenderTargetNext]; - - std::vector fProjEach; - std::vector fProjAll; - + std::vector fRenderTargetPool512; + std::vector fRenderTargetPool256; + std::vector fRenderTargetPool128; + std::vector fRenderTargetPool64; + std::vector fRenderTargetPool32; + enum + { + kMaxRenderTargetNext = 10 + }; + uint32_t fRenderTargetNext[kMaxRenderTargetNext]; + + std::vector fProjEach; + std::vector fProjAll; + uint32_t fCurrRenderLayer; - - void PushCurrentLightSources(); - void PopCurrentLightSources(); - plMetalLights fLights; - std::vector fLightSourceStack; - + + void PushCurrentLightSources(); + void PopCurrentLightSources(); + plMetalLights fLights; + std::vector fLightSourceStack; + static plMetalEnumerate enumerator; - - plTextFont* fTextFontRefList; - + + plTextFont* fTextFontRefList; + NS::AutoreleasePool* fCurrentPool; - + /// Describes the state for the "fixed function" shader. - struct plMetalPipelineCurrentState { - + struct plMetalPipelineCurrentState + { // notes state of a given layer for a draw pass // index is the offset from the curent root layer // for the draw pass, not the overall index in the // material - struct plMetalPipelineLayerState { + struct plMetalPipelineLayerState + { hsGMatState::hsGMatClampFlags clampFlag; } layerStates[8]; - - std::optional fCurrentCullMode; - const MTL::RenderPipelineState* fCurrentPipelineState; - MTL::Buffer* fCurrentVertexBuffer; - MTL::DepthStencilState* fCurrentDepthStencilState; - + + std::optional fCurrentCullMode; + const MTL::RenderPipelineState* fCurrentPipelineState; + MTL::Buffer* fCurrentVertexBuffer; + MTL::DepthStencilState* fCurrentDepthStencilState; + void Reset(); } fState; }; -#endif // _plGLPipeline_inc_ +#endif // _plGLPipeline_inc_ diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp index 48a6550bf5..827ec1a6b6 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp @@ -41,28 +41,29 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ #include "plMetalPipelineState.h" + #include "plDrawable/plGBufferGroup.h" -#include "plSurface/plLayerInterface.h" -#include "plSurface/hsGMaterial.h" -#include "plMetalDevice.h" -#include "plGImage/plMipmap.h" #include "plGImage/plCubicEnvironmap.h" -#include "plPipeline/plCubicRenderTarget.h" -#include "plPipeline/plRenderTarget.h" +#include "plGImage/plMipmap.h" #include "plMetalDevice.h" #include "plMetalMaterialShaderRef.h" +#include "plPipeline/plCubicRenderTarget.h" +#include "plPipeline/plRenderTarget.h" +#include "plSurface/hsGMaterial.h" +#include "plSurface/plLayerInterface.h" -size_t plMetalPipelineState::GetHash() const { +size_t plMetalPipelineState::GetHash() const +{ return std::hash()(GetID()); } plMetalPipelineState::plMetalPipelineState(plMetalDevice* device) -: fDevice(device) + : fDevice(device) { } plMetalRenderSpanPipelineState::plMetalRenderSpanPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef) -: plMetalPipelineState(device) + : plMetalPipelineState(device) { fNumUVs = plGBufferGroup::CalcNumUVs(vRef->fFormat); fNumWeights = (vRef->fFormat & plGBufferGroup::kSkinWeightMask) >> 4; @@ -76,7 +77,8 @@ void plMetalRenderSpanPipelineState::GetFunctionConstants(MTL::FunctionConstantV constants->setConstantValue(&fNumWeights, MTL::DataTypeUChar, FunctionConstantNumWeights); } -size_t plMetalRenderSpanPipelineState::GetHash() const { +size_t plMetalRenderSpanPipelineState::GetHash() const +{ std::size_t h1 = std::hash()(fNumUVs); std::size_t h2 = std::hash()(fNumWeights); std::size_t h3 = std::hash()(fHasSkinIndices); @@ -84,17 +86,19 @@ size_t plMetalRenderSpanPipelineState::GetHash() const { return h1 ^ h2 ^ h3 ^ plMetalPipelineState::GetHash(); } -plMetalDevice::plMetalLinkedPipeline* plMetalPipelineState::GetRenderPipelineState() { +plMetalDevice::plMetalLinkedPipeline* plMetalPipelineState::GetRenderPipelineState() +{ return fDevice->PipelineState(this); } -void plMetalPipelineState::PrewarmRenderPipelineState() { +void plMetalPipelineState::PrewarmRenderPipelineState() +{ fDevice->PrewarmPipelineStateFor(this); } - -plMetalMaterialPassPipelineState::plMetalMaterialPassPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef, const plMetalFragmentShaderDescription &description) -: plMetalRenderSpanPipelineState(device, vRef) { +plMetalMaterialPassPipelineState::plMetalMaterialPassPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef, const plMetalFragmentShaderDescription& description) + : plMetalRenderSpanPipelineState(device, vRef) +{ fFragmentShaderDescription = description; fFragmentShaderDescription.CacheHash(); } @@ -108,54 +112,56 @@ void plMetalMaterialPassPipelineState::GetFunctionConstants(MTL::FunctionConstan constants->setConstantValues(&fFragmentShaderDescription.miscFlags, MTL::DataTypeUInt, NS::Range(FunctionConstantLayerFlags, 8)); } -size_t plMetalMaterialPassPipelineState::GetHash() const { +size_t plMetalMaterialPassPipelineState::GetHash() const +{ std::size_t value = plMetalRenderSpanPipelineState::GetHash(); value ^= fFragmentShaderDescription.GetHash(); return value; } -void plMetalRenderSpanPipelineState::ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor) { +void plMetalRenderSpanPipelineState::ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor) +{ int vertOffset = 0; int skinWeightOffset = vertOffset + (sizeof(float) * 3); - if(this->fHasSkinIndices) { + if (this->fHasSkinIndices) { skinWeightOffset += sizeof(uint32_t); } int normOffset = skinWeightOffset + (sizeof(float) * this->fNumWeights); int colorOffset = normOffset + (sizeof(float) * 3); int baseUvOffset = colorOffset + (sizeof(uint32_t) * 2); int stride = baseUvOffset + (sizeof(float) * 3 * this->fNumUVs); - + vertexDescriptor->attributes()->object(VertexAttributePosition)->setFormat(MTL::VertexFormatFloat3); vertexDescriptor->attributes()->object(VertexAttributePosition)->setBufferIndex(0); vertexDescriptor->attributes()->object(VertexAttributePosition)->setOffset(vertOffset); - + vertexDescriptor->attributes()->object(VertexAttributeNormal)->setFormat(MTL::VertexFormatFloat3); vertexDescriptor->attributes()->object(VertexAttributeNormal)->setBufferIndex(0); vertexDescriptor->attributes()->object(VertexAttributeNormal)->setOffset(normOffset); - - if(this->fNumWeights > 0) { + + if (this->fNumWeights > 0) { int weightOneOffset = skinWeightOffset; - + vertexDescriptor->attributes()->object(VertexAttributeWeights)->setFormat(MTL::VertexFormatFloat); vertexDescriptor->attributes()->object(VertexAttributeWeights)->setBufferIndex(0); vertexDescriptor->attributes()->object(VertexAttributeWeights)->setOffset(weightOneOffset); } - - for(int i=0; ifNumUVs; i++) { - vertexDescriptor->attributes()->object(VertexAttributeTexcoord+i)->setFormat(MTL::VertexFormatFloat3); - vertexDescriptor->attributes()->object(VertexAttributeTexcoord+i)->setBufferIndex(0); - vertexDescriptor->attributes()->object(VertexAttributeTexcoord+i)->setOffset(baseUvOffset + (i * sizeof(float) * 3)); + + for (int i = 0; i < this->fNumUVs; i++) { + vertexDescriptor->attributes()->object(VertexAttributeTexcoord + i)->setFormat(MTL::VertexFormatFloat3); + vertexDescriptor->attributes()->object(VertexAttributeTexcoord + i)->setBufferIndex(0); + vertexDescriptor->attributes()->object(VertexAttributeTexcoord + i)->setOffset(baseUvOffset + (i * sizeof(float) * 3)); } - + vertexDescriptor->attributes()->object(VertexAttributeColor)->setFormat(MTL::VertexFormatUChar4); vertexDescriptor->attributes()->object(VertexAttributeColor)->setBufferIndex(0); vertexDescriptor->attributes()->object(VertexAttributeColor)->setOffset(colorOffset); - + vertexDescriptor->layouts()->object(VertexAttributePosition)->setStride(stride); } -void plMetalRenderSpanPipelineState::ConfigureBlendMode(const uint32_t blendMode, MTL::RenderPipelineColorAttachmentDescriptor *descriptor) +void plMetalRenderSpanPipelineState::ConfigureBlendMode(const uint32_t blendMode, MTL::RenderPipelineColorAttachmentDescriptor* descriptor) { if (blendMode & hsGMatState::kBlendNoColor) { //printf("glBlendFunc(GL_ZERO, GL_ONE);\n"); @@ -177,7 +183,8 @@ void plMetalRenderSpanPipelineState::ConfigureBlendMode(const uint32_t blendMode descriptor->setSourceRGBBlendFactor(MTL::BlendFactorOne); } else { //printf("glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);\n"); - descriptor->setSourceRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha);; + descriptor->setSourceRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha); + ; } descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorSourceAlpha); } else { @@ -251,16 +258,15 @@ void plMetalRenderSpanPipelineState::ConfigureBlendMode(const uint32_t blendMode descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorZero); descriptor->setSourceAlphaBlendFactor(MTL::BlendFactorOne); descriptor->setDestinationAlphaBlendFactor(MTL::BlendFactorZero); - + /*descriptor->colorAttachments()->object(0)->setSourceRGBBlendFactor(MTL::BlendFactorOne); descriptor->colorAttachments()->object(0)->setSourceAlphaBlendFactor(MTL::BlendFactorOne); descriptor->colorAttachments()->object(0)->setDestinationRGBBlendFactor(MTL::BlendFactorZero); descriptor->colorAttachments()->object(0)->setDestinationAlphaBlendFactor(MTL::BlendFactorZero);*/ break; - default: - { - /*hsAssert(false, "Too many blend modes specified in material"); + default: { + /*hsAssert(false, "Too many blend modes specified in material"); plLayer* lay = plLayer::ConvertNoRef(fCurrMaterial->GetLayer(fCurrLayerIdx)->BottomOfStack()); if( lay ) { @@ -273,50 +279,56 @@ void plMetalRenderSpanPipelineState::ConfigureBlendMode(const uint32_t blendMode lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAdd); } }*/ - } - break; + } break; } } -MTL::Function* plMetalMaterialPassPipelineState::GetVertexFunction(MTL::Library* library) { - NS::Error* error = nullptr; +MTL::Function* plMetalMaterialPassPipelineState::GetVertexFunction(MTL::Library* library) +{ + NS::Error* error = nullptr; MTL::FunctionConstantValues* constants = MTL::FunctionConstantValues::alloc()->init()->autorelease(); this->GetFunctionConstants(constants); MTL::Function* function = library->newFunction( - NS::String::string("pipelineVertexShader", NS::ASCIIStringEncoding), - MakeFunctionConstants(), - &error - )->autorelease(); + NS::String::string("pipelineVertexShader", NS::ASCIIStringEncoding), + MakeFunctionConstants(), + &error) + ->autorelease(); return function; } -MTL::Function* plMetalMaterialPassPipelineState::GetFragmentFunction(MTL::Library* library) { +MTL::Function* plMetalMaterialPassPipelineState::GetFragmentFunction(MTL::Library* library) +{ return library->newFunction( - NS::String::string("pipelineFragmentShader", NS::ASCIIStringEncoding), - MakeFunctionConstants(), - (NS::Error **)NULL - )->autorelease(); + NS::String::string("pipelineFragmentShader", NS::ASCIIStringEncoding), + MakeFunctionConstants(), + (NS::Error**)NULL) + ->autorelease(); } -plMetalMaterialPassPipelineState::~plMetalMaterialPassPipelineState() { +plMetalMaterialPassPipelineState::~plMetalMaterialPassPipelineState() +{ } -const NS::String* plMetalMaterialPassPipelineState::GetDescription() { +const NS::String* plMetalMaterialPassPipelineState::GetDescription() +{ return NS::MakeConstantString("Material Pipeline"); } -void plMetalMaterialPassPipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) { +void plMetalMaterialPassPipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) +{ uint32_t blendMode = fFragmentShaderDescription.blendModes[0]; ConfigureBlendMode(blendMode, descriptor); } -void plMetalFragmentShaderDescription::Populate(const plLayerInterface* layPtr, const uint8_t index) { +void plMetalFragmentShaderDescription::Populate(const plLayerInterface* layPtr, const uint8_t index) +{ blendModes[index] = layPtr->GetBlendFlags(); miscFlags[index] = layPtr->GetMiscFlags(); PopulateTextureInfo(layPtr, index); } -void plMetalFragmentShaderDescription::PopulateTextureInfo(const plLayerInterface* layPtr, const uint8_t index) { +void plMetalFragmentShaderDescription::PopulateTextureInfo(const plLayerInterface* layPtr, const uint8_t index) +{ plBitmap* texture = layPtr->GetTexture(); if (texture != nullptr) { if (plCubicEnvironmap::ConvertNoRef(texture) != nullptr || plCubicRenderTarget::ConvertNoRef(texture) != nullptr) { @@ -326,34 +338,37 @@ void plMetalFragmentShaderDescription::PopulateTextureInfo(const plLayerInterfac } else { passTypes[index] = PassTypeColor; } - + } else { passTypes[index] = PassTypeColor; } - } -bool plMetalMaterialPassPipelineState::IsEqual(const plMetalPipelineState &p) const { +bool plMetalMaterialPassPipelineState::IsEqual(const plMetalPipelineState& p) const +{ return plMetalRenderSpanPipelineState::IsEqual(p) && static_cast(&p)->fFragmentShaderDescription == this->fFragmentShaderDescription; } -MTL::Function* plMetalRenderShadowPipelineState::GetVertexFunction(MTL::Library* library) { +MTL::Function* plMetalRenderShadowPipelineState::GetVertexFunction(MTL::Library* library) +{ return library->newFunction( - NS::String::string("shadowCastVertexShader", NS::ASCIIStringEncoding), - MakeFunctionConstants(), - (NS::Error **)NULL - )->autorelease(); + NS::String::string("shadowCastVertexShader", NS::ASCIIStringEncoding), + MakeFunctionConstants(), + (NS::Error**)NULL) + ->autorelease(); } -MTL::Function* plMetalRenderShadowPipelineState::GetFragmentFunction(MTL::Library* library) { +MTL::Function* plMetalRenderShadowPipelineState::GetFragmentFunction(MTL::Library* library) +{ return library->newFunction( - NS::String::string("shadowCastFragmentShader", NS::ASCIIStringEncoding), - MakeFunctionConstants(), - (NS::Error **)NULL - )->autorelease(); + NS::String::string("shadowCastFragmentShader", NS::ASCIIStringEncoding), + MakeFunctionConstants(), + (NS::Error**)NULL) + ->autorelease(); } -void plMetalRenderShadowPipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) { +void plMetalRenderShadowPipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) +{ descriptor->setSourceRGBBlendFactor(MTL::BlendFactorZero); descriptor->setSourceAlphaBlendFactor(MTL::BlendFactorOne); descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceColor); @@ -362,78 +377,72 @@ void plMetalRenderShadowPipelineState::ConfigureBlend(MTL::RenderPipelineColorAt const MTL::Function* plMetalRenderShadowCasterPipelineState::GetVertexFunction(MTL::Library* library) { - NS::Error* error = nullptr; + NS::Error* error = nullptr; MTL::Function* function = library->newFunction( - NS::MakeConstantString("shadowVertexShader"), - MakeFunctionConstants(), - &error - )->autorelease(); + NS::MakeConstantString("shadowVertexShader"), + MakeFunctionConstants(), + &error) + ->autorelease(); return function; } const MTL::Function* plMetalRenderShadowCasterPipelineState::GetFragmentFunction(MTL::Library* library) { - NS::Error* error = nullptr; + NS::Error* error = nullptr; MTL::Function* function = library->newFunction( - NS::MakeConstantString("shadowFragmentShader"), - MakeFunctionConstants(), - &error - )->autorelease(); + NS::MakeConstantString("shadowFragmentShader"), + MakeFunctionConstants(), + &error) + ->autorelease(); return function; } -const MTL::Function* plMetalDynamicMaterialPipelineState::GetVertexFunction(MTL::Library *library) { +const MTL::Function* plMetalDynamicMaterialPipelineState::GetVertexFunction(MTL::Library* library) +{ MTL::FunctionConstantValues* functionConstants = MakeFunctionConstants(); - MTL::Function* vertFunction; - switch(fVertexShaderID) { + MTL::Function* vertFunction; + switch (fVertexShaderID) { case plShaderID::vs_WaveFixedFin7: vertFunction = library->newFunction( - NS::String::string("vs_WaveFixedFin7", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_WaveFixedFin7", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::vs_CompCosines: vertFunction = library->newFunction( - NS::String::string("vs_CompCosines", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_CompCosines", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::vs_BiasNormals: vertFunction = library->newFunction( - NS::String::string("vs_BiasNormals", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_BiasNormals", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::vs_GrassShader: vertFunction = library->newFunction( - NS::String::string("vs_GrassShader", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_GrassShader", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::vs_WaveDecEnv_7: vertFunction = library->newFunction( - NS::String::string("vs_WaveDecEnv_7", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_WaveDecEnv_7", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::vs_WaveDec1Lay_7: vertFunction = library->newFunction( - NS::String::string("vs_WaveDec1Lay_7", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_WaveDec1Lay_7", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::vs_WaveRip7: vertFunction = library->newFunction( - NS::String::string("vs_WaveRip7", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("vs_WaveRip7", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; default: hsAssert(0, "unknown shader requested"); @@ -441,58 +450,52 @@ const MTL::Function* plMetalDynamicMaterialPipelineState::GetVertexFunction(MTL: return vertFunction; } -const MTL::Function* plMetalDynamicMaterialPipelineState::GetFragmentFunction(MTL::Library *library) { +const MTL::Function* plMetalDynamicMaterialPipelineState::GetFragmentFunction(MTL::Library* library) +{ MTL::FunctionConstantValues* functionConstants = MakeFunctionConstants(); - MTL::Function* fragFunction; - switch(fFragmentShaderID) { + MTL::Function* fragFunction; + switch (fFragmentShaderID) { case plShaderID::ps_WaveFixed: fragFunction = library->newFunction( - NS::String::string("ps_WaveFixed", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_WaveFixed", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::ps_MoreCosines: fragFunction = library->newFunction( - NS::String::string("ps_CompCosines", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_CompCosines", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::ps_BiasNormals: fragFunction = library->newFunction( - NS::String::string("ps_BiasNormals", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_BiasNormals", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::ps_GrassShader: fragFunction = library->newFunction( - NS::String::string("ps_GrassShader", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_GrassShader", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::ps_WaveDecEnv: fragFunction = library->newFunction( - NS::String::string("ps_WaveDecEnv", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_WaveDecEnv", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::ps_CbaseAbase: fragFunction = library->newFunction( - NS::String::string("ps_CbaseAbase", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_CbaseAbase", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; case plShaderID::ps_WaveRip: fragFunction = library->newFunction( - NS::String::string("ps_WaveRip", NS::ASCIIStringEncoding), - functionConstants, - (NS::Error **)nullptr - ); + NS::String::string("ps_WaveRip", NS::ASCIIStringEncoding), + functionConstants, + (NS::Error**)nullptr); break; default: hsAssert(0, "unknown shader requested"); diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.h index 73e867d76c..827d677928 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.h @@ -44,119 +44,132 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define plMetalPipelineState_hpp #include + #include #include "plMetalDevice.h" #include "plSurface/plShaderTable.h" -class plMetalPipelineState { -public: +class plMetalPipelineState +{ + public: plMetalPipelineState(plMetalDevice* device); plMetalDevice::plMetalLinkedPipeline* GetRenderPipelineState(); - void PrewarmRenderPipelineState(); - bool operator==(const plMetalPipelineState& p) const { + void PrewarmRenderPipelineState(); + bool operator==(const plMetalPipelineState& p) const + { if ((&p)->GetID() != this->GetID()) { return false; } else { return IsEqual(p); } } - virtual size_t GetHash() const; - virtual bool IsEqual(const plMetalPipelineState &p) const = 0; - virtual uint16_t GetID() const { return 0; }; + virtual size_t GetHash() const; + virtual bool IsEqual(const plMetalPipelineState& p) const = 0; + virtual uint16_t GetID() const { return 0; }; virtual plMetalPipelineState* Clone() = 0; - + // - virtual const MTL::Function* GetVertexFunction(MTL::Library* library) = 0; - virtual const MTL::Function* GetFragmentFunction(MTL::Library* library) = 0; - virtual const NS::String* GetDescription() = 0; - + virtual const MTL::Function* GetVertexFunction(MTL::Library* library) = 0; + virtual const MTL::Function* GetFragmentFunction(MTL::Library* library) = 0; + virtual const NS::String* GetDescription() = 0; + virtual void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) = 0; virtual void ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor) = 0; virtual ~plMetalPipelineState() = default; -protected: - plMetalDevice* fDevice; - virtual void GetFunctionConstants(MTL::FunctionConstantValues*) const = 0; - MTL::FunctionConstantValues* MakeFunctionConstants() { + + protected: + plMetalDevice* fDevice; + virtual void GetFunctionConstants(MTL::FunctionConstantValues*) const = 0; + MTL::FunctionConstantValues* MakeFunctionConstants() + { MTL::FunctionConstantValues* constants = MTL::FunctionConstantValues::alloc()->init()->autorelease(); this->GetFunctionConstants(constants); return constants; } }; -class plMetalRenderSpanPipelineState: public plMetalPipelineState { -public: +class plMetalRenderSpanPipelineState : public plMetalPipelineState +{ + public: plMetalRenderSpanPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef); - virtual bool IsEqual(const plMetalPipelineState &p) const { - const plMetalRenderSpanPipelineState *renderSpanPipelineSate = static_cast(&p); - if( !renderSpanPipelineSate ) { + virtual bool IsEqual(const plMetalPipelineState& p) const + { + const plMetalRenderSpanPipelineState* renderSpanPipelineSate = static_cast(&p); + if (!renderSpanPipelineSate) { return false; } return renderSpanPipelineSate->fNumUVs == fNumUVs && renderSpanPipelineSate->fNumWeights == fNumWeights && renderSpanPipelineSate->fHasSkinIndices == fHasSkinIndices; }; virtual size_t GetHash() const; - - virtual void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) = 0; + + virtual void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) = 0; virtual void ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor); - - void ConfigureBlendMode(const uint32_t blendMode, MTL::RenderPipelineColorAttachmentDescriptor *descriptor); -protected: - uint8_t fNumUVs; - uint8_t fNumWeights; - bool fHasSkinIndices; - virtual void GetFunctionConstants(MTL::FunctionConstantValues*) const; - MTL::FunctionConstantValues* MakeFunctionConstants() { + + void ConfigureBlendMode(const uint32_t blendMode, MTL::RenderPipelineColorAttachmentDescriptor* descriptor); + + protected: + uint8_t fNumUVs; + uint8_t fNumWeights; + bool fHasSkinIndices; + virtual void GetFunctionConstants(MTL::FunctionConstantValues*) const; + MTL::FunctionConstantValues* MakeFunctionConstants() + { MTL::FunctionConstantValues* constants = MTL::FunctionConstantValues::alloc()->init()->autorelease(); this->GetFunctionConstants(constants); return constants; } }; -struct plMetalFragmentShaderDescription { - uint8_t passTypes[8]; - uint32_t blendModes[8]; - uint32_t miscFlags[8]; - uint8_t numLayers; - - size_t hash; - - bool operator==(const plMetalFragmentShaderDescription &p) const { +struct plMetalFragmentShaderDescription +{ + uint8_t passTypes[8]; + uint32_t blendModes[8]; + uint32_t miscFlags[8]; + uint8_t numLayers; + + size_t hash; + + bool operator==(const plMetalFragmentShaderDescription& p) const + { bool match = numLayers == p.numLayers && memcmp(passTypes, p.passTypes, sizeof(passTypes)) == 0 && memcmp(blendModes, p.blendModes, sizeof(blendModes)) == 0 && memcmp(miscFlags, p.miscFlags, sizeof(miscFlags)) == 0; return match; } - - void CacheHash() { - if(!hash) + + void CacheHash() + { + if (!hash) hash = GetHash(); } - - size_t GetHash() const { - if(hash) + + size_t GetHash() const + { + if (hash) return hash; - + std::size_t value = std::hash()(numLayers); value ^= std::hash()(numLayers); - - for(int i=0;i<8;i++){ - value ^= std::hash()( blendModes[i] ); + + for (int i = 0; i < 8; i++) { + value ^= std::hash()(blendModes[i]); } - - for(int i=0;i<8;i++){ - value ^= std::hash()( miscFlags[i] ); + + for (int i = 0; i < 8; i++) { + value ^= std::hash()(miscFlags[i]); } - - for(int i=0;i<8;i++){ - value ^= std::hash()( passTypes[i] ); + + for (int i = 0; i < 8; i++) { + value ^= std::hash()(passTypes[i]); } - + return value; } - + void Populate(const plLayerInterface* layPtr, const uint8_t index); void PopulateTextureInfo(const plLayerInterface* layPtr, const uint8_t index); }; -template<> +template <> struct std::hash { std::size_t operator()(plMetalFragmentShaderDescription const& s) const noexcept @@ -165,123 +178,139 @@ struct std::hash } }; -class plMetalMaterialPassPipelineState: public plMetalRenderSpanPipelineState { -public: - plMetalMaterialPassPipelineState(plMetalDevice* device, const plMetalVertexBufferRef *vRef, const plMetalFragmentShaderDescription &description); +class plMetalMaterialPassPipelineState : public plMetalRenderSpanPipelineState +{ + public: + plMetalMaterialPassPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef, const plMetalFragmentShaderDescription& description); virtual size_t GetHash() const override; - MTL::Function* GetVertexFunction(MTL::Library* library) override; - MTL::Function* GetFragmentFunction(MTL::Library* library) override; - - virtual const NS::String* GetDescription() override; - - void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) override; - - virtual bool IsEqual(const plMetalPipelineState &p) const override; - + MTL::Function* GetVertexFunction(MTL::Library* library) override; + MTL::Function* GetFragmentFunction(MTL::Library* library) override; + + virtual const NS::String* GetDescription() override; + + void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override; + + virtual bool IsEqual(const plMetalPipelineState& p) const override; + virtual uint16_t GetID() const override { return 1; }; - - virtual plMetalPipelineState* Clone() override { + + virtual plMetalPipelineState* Clone() override + { return new plMetalMaterialPassPipelineState(*this); } ~plMetalMaterialPassPipelineState(); virtual void GetFunctionConstants(MTL::FunctionConstantValues*) const override; -protected: + + protected: plMetalFragmentShaderDescription fFragmentShaderDescription; }; -class plMetalRenderShadowCasterPipelineState: public plMetalRenderSpanPipelineState { -public: +class plMetalRenderShadowCasterPipelineState : public plMetalRenderSpanPipelineState +{ + public: plMetalRenderShadowCasterPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef) - : plMetalRenderSpanPipelineState(device, vRef) { - + : plMetalRenderSpanPipelineState(device, vRef) + { } - const MTL::Function* GetVertexFunction(MTL::Library* library) override; - const MTL::Function* GetFragmentFunction(MTL::Library* library) override; - - const NS::String* GetDescription() override { + const MTL::Function* GetVertexFunction(MTL::Library* library) override; + const MTL::Function* GetFragmentFunction(MTL::Library* library) override; + + const NS::String* GetDescription() override + { return NS::MakeConstantString("Shadow Caster Pipeline"); }; - - void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) override { + + void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override + { descriptor->setSourceRGBBlendFactor(MTL::BlendFactorOne); descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorSourceAlpha); }; virtual uint16_t GetID() const override { return 2; }; - - - virtual plMetalPipelineState* Clone() override { + + virtual plMetalPipelineState* Clone() override + { return new plMetalRenderShadowCasterPipelineState(*this); } - }; -class plMetalRenderShadowPipelineState: public plMetalMaterialPassPipelineState { -public: - plMetalRenderShadowPipelineState(plMetalDevice* device, plMetalVertexBufferRef *vRef, const plMetalFragmentShaderDescription &description) - : plMetalMaterialPassPipelineState(device, vRef, description) { +class plMetalRenderShadowPipelineState : public plMetalMaterialPassPipelineState +{ + public: + plMetalRenderShadowPipelineState(plMetalDevice* device, plMetalVertexBufferRef* vRef, const plMetalFragmentShaderDescription& description) + : plMetalMaterialPassPipelineState(device, vRef, description) + { } - - const NS::String* GetDescription() override { + + const NS::String* GetDescription() override + { return NS::MakeConstantString("Shadow Span Render Pipeline"); }; - MTL::Function* GetVertexFunction(MTL::Library* library) override; - MTL::Function* GetFragmentFunction(MTL::Library* library) override; - void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) override; - virtual uint16_t GetID() const override { return 3; } ; - - virtual plMetalPipelineState* Clone() override { + MTL::Function* GetVertexFunction(MTL::Library* library) override; + MTL::Function* GetFragmentFunction(MTL::Library* library) override; + void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override; + virtual uint16_t GetID() const override { return 3; }; + + virtual plMetalPipelineState* Clone() override + { return new plMetalRenderShadowPipelineState(*this); } }; -class plMetalDynamicMaterialPipelineState: public plMetalRenderSpanPipelineState { -public: - plMetalDynamicMaterialPipelineState(plMetalDevice* device, const plMetalVertexBufferRef *vRef, uint32_t blendMode, plShaderID::ID vertexShaderID, plShaderID::ID fragmentShaderID) - : plMetalRenderSpanPipelineState(device, vRef), - fVertexShaderID(vertexShaderID), - fFragmentShaderID(fragmentShaderID), - fBlendMode(blendMode) { - - }; - - virtual plMetalPipelineState* Clone() override { +class plMetalDynamicMaterialPipelineState : public plMetalRenderSpanPipelineState +{ + public: + plMetalDynamicMaterialPipelineState(plMetalDevice* device, const plMetalVertexBufferRef* vRef, uint32_t blendMode, plShaderID::ID vertexShaderID, plShaderID::ID fragmentShaderID) + : plMetalRenderSpanPipelineState(device, vRef), + fVertexShaderID(vertexShaderID), + fFragmentShaderID(fragmentShaderID), + fBlendMode(blendMode){ + + }; + + virtual plMetalPipelineState* Clone() override + { return new plMetalDynamicMaterialPipelineState(*this); } - - bool IsEqual(const plMetalPipelineState &p) const override { + + bool IsEqual(const plMetalPipelineState& p) const override + { const plMetalDynamicMaterialPipelineState* dynamicState = static_cast(&p); if (!dynamicState) { return false; } - return plMetalRenderSpanPipelineState::IsEqual(p) && dynamicState->fFragmentShaderID == fFragmentShaderID && dynamicState->fVertexShaderID == fVertexShaderID && dynamicState->fBlendMode == fBlendMode; + return plMetalRenderSpanPipelineState::IsEqual(p) && dynamicState->fFragmentShaderID == fFragmentShaderID && dynamicState->fVertexShaderID == fVertexShaderID && dynamicState->fBlendMode == fBlendMode; } - - size_t GetHash() const override { + + size_t GetHash() const override + { std::size_t value = std::hash()(fFragmentShaderID); value ^= std::hash()(fVertexShaderID); value ^= std::hash()(fVertexShaderID); value ^= std::hash()(fBlendMode); - + return value ^ plMetalRenderSpanPipelineState::GetHash(); } - - const MTL::Function* GetVertexFunction(MTL::Library *library) override; - const MTL::Function* GetFragmentFunction(MTL::Library *library) override; - - const NS::String *GetDescription() override { + + const MTL::Function* GetVertexFunction(MTL::Library* library) override; + const MTL::Function* GetFragmentFunction(MTL::Library* library) override; + + const NS::String* GetDescription() override + { return NS::MakeConstantString("Dynamic Shader"); } - - void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) override { + + void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override + { ConfigureBlendMode(fBlendMode, descriptor); } -protected: - plShaderID::ID fVertexShaderID; - plShaderID::ID fFragmentShaderID; - uint32_t fBlendMode; + + protected: + plShaderID::ID fVertexShaderID; + plShaderID::ID fFragmentShaderID; + uint32_t fBlendMode; }; -template<> +template <> struct std::hash { std::size_t operator()(plMetalPipelineState const& s) const noexcept @@ -290,53 +319,60 @@ struct std::hash } }; -class plMetalClearPipelineState: public plMetalPipelineState { -public: - plMetalClearPipelineState(plMetalDevice *device, bool shouldClearColor, bool shouldClearDepth): - plMetalPipelineState(device) +class plMetalClearPipelineState : public plMetalPipelineState +{ + public: + plMetalClearPipelineState(plMetalDevice* device, bool shouldClearColor, bool shouldClearDepth) : plMetalPipelineState(device) { fShouldClearDepth = shouldClearDepth; fShouldClearColor = shouldClearColor; } - - virtual bool IsEqual(const plMetalPipelineState &p) const override { + + virtual bool IsEqual(const plMetalPipelineState& p) const override + { const plMetalClearPipelineState* clearState = static_cast(&p); if (!clearState) { return false; } return clearState->fShouldClearDepth == fShouldClearDepth && fShouldClearColor == clearState->fShouldClearColor; }; - - virtual uint16_t GetID() const override { return 4; }; - virtual plMetalPipelineState* Clone() override { + + virtual uint16_t GetID() const override { return 4; }; + virtual plMetalPipelineState* Clone() override + { return new plMetalClearPipelineState(*this); }; - + // - virtual const MTL::Function* GetVertexFunction(MTL::Library* library) override { + virtual const MTL::Function* GetVertexFunction(MTL::Library* library) override + { return library->newFunction(NS::MakeConstantString("clearVertex")); }; - virtual const MTL::Function* GetFragmentFunction(MTL::Library* library) override { + virtual const MTL::Function* GetFragmentFunction(MTL::Library* library) override + { return library->newFunction(NS::MakeConstantString("clearFragment"), MakeFunctionConstants(), - (NS::Error **)NULL - )->autorelease(); + (NS::Error**)NULL) + ->autorelease(); }; - virtual const NS::String* GetDescription() override { + virtual const NS::String* GetDescription() override + { return NS::MakeConstantString("Clear"); }; - - virtual void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override { + + virtual void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override + { //if (fShouldClearColor) { - descriptor->setSourceRGBBlendFactor(MTL::BlendFactorOne); - descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorZero); + descriptor->setSourceRGBBlendFactor(MTL::BlendFactorOne); + descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorZero); //} else { // descriptor->setSourceRGBBlendFactor(MTL::BlendFactorZero); // descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorOne); //} }; - - virtual void ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor) override { + + virtual void ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor) override + { vertexDescriptor->attributes()->object(0)->setFormat(MTL::VertexFormatFloat2); vertexDescriptor->attributes()->object(0)->setOffset(0); vertexDescriptor->attributes()->object(0)->setBufferIndex(0); @@ -344,25 +380,25 @@ class plMetalClearPipelineState: public plMetalPipelineState { vertexDescriptor->layouts()->object(0)->setStepFunction(MTL::VertexStepFunctionPerVertex); vertexDescriptor->layouts()->object(0)->setStepRate(1); }; - - virtual void GetFunctionConstants(MTL::FunctionConstantValues* values) const override { + + virtual void GetFunctionConstants(MTL::FunctionConstantValues* values) const override + { values->setConstantValue(&fShouldClearDepth, MTL::DataTypeBool, NS::UInteger(0)); values->setConstantValue(&fShouldClearColor, MTL::DataTypeBool, NS::UInteger(1)); } - - virtual size_t GetHash() const override { + + virtual size_t GetHash() const override + { std::size_t value = plMetalPipelineState::GetHash(); value ^= std::hash()(fShouldClearColor); value ^= std::hash()(fShouldClearDepth); - + return value; } - -private: - + + private: bool fShouldClearColor; bool fShouldClearDepth; - }; #endif /* plMetalPipelineState_hpp */ diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.cpp index 16cc251dd7..ed0d60017a 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.cpp @@ -41,15 +41,16 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ #include "plMetalPlateManager.h" -#include "plMetalPipeline.h" + #include + #include "ShaderTypes.h" +#include "plMetalPipeline.h" -plMetalPlateManager::plMetalPlateManager(plMetalPipeline* pipe) +plMetalPlateManager::plMetalPlateManager(plMetalPipeline *pipe) : plPlateManager(pipe), - fVtxBuffer(0) + fVtxBuffer(0) { - MTL::DepthStencilDescriptor *depthDescriptor = MTL::DepthStencilDescriptor::alloc()->init(); depthDescriptor->setDepthCompareFunction(MTL::CompareFunctionAlways); depthDescriptor->setDepthWriteEnabled(false); @@ -60,7 +61,7 @@ plMetalPlateManager::plMetalPlateManager(plMetalPipeline* pipe) void plMetalPlateManager::ICreateGeometry() { plMetalPipeline *pipeline = (plMetalPipeline *)fOwner; - if(!fVtxBuffer) { + if (!fVtxBuffer) { struct plateVertexBuffer vertexBuffer; vertexBuffer.vertices[0].Set(-0.5f, -0.5f); vertexBuffer.uv[0].Set(0.0f, 0.0f); @@ -75,17 +76,18 @@ void plMetalPlateManager::ICreateGeometry() vertexBuffer.uv[3].Set(1.0f, 1.0f); uint16_t indices[6] = {0, 1, 2, 1, 2, 3}; - + fVtxBuffer = pipeline->fDevice.fMetalDevice->newBuffer(&vertexBuffer, sizeof(plateVertexBuffer), MTL::StorageModeManaged); fVtxBuffer->retain(); idxBuffer = pipeline->fDevice.fMetalDevice->newBuffer(&indices, sizeof(uint16_t) * 6, MTL::StorageModeManaged); } } -void plMetalPlateManager::EncodeDraw(MTL::RenderCommandEncoder *encoder) { +void plMetalPlateManager::EncodeDraw(MTL::RenderCommandEncoder *encoder) +{ encoder->setVertexBuffer(fVtxBuffer, 0, VertexAttributePosition); encoder->setVertexBuffer(fVtxBuffer, offsetof(plateVertexBuffer, uv), VertexAttributeTexcoord); - + encoder->drawIndexedPrimitives(MTL::PrimitiveTypeTriangle, 6, MTL::IndexTypeUInt16, idxBuffer, 0); } @@ -98,10 +100,11 @@ void plMetalPlateManager::IReleaseGeometry() } } -void plMetalPlateManager::IDrawToDevice(plPipeline *pipe) { +void plMetalPlateManager::IDrawToDevice(plPipeline *pipe) +{ plMetalPipeline *pipeline = (plMetalPipeline *)pipe; - plPlate* plate = nullptr; - + plPlate *plate = nullptr; + for (plate = fPlates; plate != nullptr; plate = plate->GetNext()) { if (plate->IsVisible()) { pipeline->IDrawPlate(plate); @@ -114,46 +117,51 @@ plMetalPlateManager::~plMetalPlateManager() IReleaseGeometry(); } - - -bool plMetalPlatePipelineState::IsEqual(const plMetalPipelineState &p) const { +bool plMetalPlatePipelineState::IsEqual(const plMetalPipelineState &p) const +{ return true; } -plMetalPipelineState *plMetalPlatePipelineState::Clone() { +plMetalPipelineState *plMetalPlatePipelineState::Clone() +{ return new plMetalPlatePipelineState(fDevice); } -const MTL::Function *plMetalPlatePipelineState::GetVertexFunction(MTL::Library *library) { +const MTL::Function *plMetalPlatePipelineState::GetVertexFunction(MTL::Library *library) +{ return library->newFunction(NS::MakeConstantString("plateVertexShader")); } -const MTL::Function *plMetalPlatePipelineState::GetFragmentFunction(MTL::Library *library) { +const MTL::Function *plMetalPlatePipelineState::GetFragmentFunction(MTL::Library *library) +{ return library->newFunction(NS::MakeConstantString("fragmentShader")); } -const NS::String *plMetalPlatePipelineState::GetDescription() { +const NS::String *plMetalPlatePipelineState::GetDescription() +{ return NS::MakeConstantString("Plate Pipeline State"); } -void plMetalPlatePipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) { +void plMetalPlatePipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) +{ descriptor->setBlendingEnabled(true); descriptor->setSourceRGBBlendFactor(MTL::BlendFactorSourceAlpha); descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha); } -void plMetalPlatePipelineState::ConfigureVertexDescriptor(MTL::VertexDescriptor *vertexDescriptor) { +void plMetalPlatePipelineState::ConfigureVertexDescriptor(MTL::VertexDescriptor *vertexDescriptor) +{ vertexDescriptor->attributes()->object(0)->setFormat(MTL::VertexFormatFloat2); vertexDescriptor->attributes()->object(0)->setBufferIndex(VertexAttributePosition); vertexDescriptor->attributes()->object(0)->setOffset(0); vertexDescriptor->attributes()->object(1)->setFormat(MTL::VertexFormatFloat2); vertexDescriptor->attributes()->object(1)->setBufferIndex(VertexAttributeTexcoord); vertexDescriptor->attributes()->object(1)->setOffset(0); - + vertexDescriptor->layouts()->object(0)->setStride(sizeof(float) * 2); vertexDescriptor->layouts()->object(1)->setStride(sizeof(float) * 2); } -void plMetalPlatePipelineState::GetFunctionConstants(MTL::FunctionConstantValues *) const { - +void plMetalPlatePipelineState::GetFunctionConstants(MTL::FunctionConstantValues *) const +{ } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.h index dc74468cee..e2626b5880 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPlateManager.h @@ -43,52 +43,56 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef plMetalPlateManager_hpp #define plMetalPlateManager_hpp +#include #include -#include "plPipeline/plPlates.h" + #include -#include + #include "hsPoint2.h" #include "plMetalPipelineState.h" +#include "plPipeline/plPlates.h" class plMetalPipeline; class plMetalDevice; class plMetalPlatePipelineState : public plMetalPipelineState { -public: - plMetalPlatePipelineState(plMetalDevice* device): plMetalPipelineState(device) { }; - virtual bool IsEqual(const plMetalPipelineState &p) const override; - virtual uint16_t GetID() const override { return 5; }; - virtual plMetalPipelineState* Clone() override; - virtual const MTL::Function* GetVertexFunction(MTL::Library* library) override; - virtual const MTL::Function* GetFragmentFunction(MTL::Library* library) override; - virtual const NS::String* GetDescription() override; - + public: + plMetalPlatePipelineState(plMetalDevice *device) : plMetalPipelineState(device){}; + virtual bool IsEqual(const plMetalPipelineState &p) const override; + virtual uint16_t GetID() const override { return 5; }; + virtual plMetalPipelineState *Clone() override; + virtual const MTL::Function *GetVertexFunction(MTL::Library *library) override; + virtual const MTL::Function *GetFragmentFunction(MTL::Library *library) override; + virtual const NS::String *GetDescription() override; + void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) override; - + void ConfigureVertexDescriptor(MTL::VertexDescriptor *vertexDescriptor) override; - + void GetFunctionConstants(MTL::FunctionConstantValues *) const override; - }; class plMetalPlateManager : public plPlateManager { friend class plMetalPipeline; -public: - plMetalPlateManager(plMetalPipeline* pipe); + + public: + plMetalPlateManager(plMetalPipeline *pipe); void IDrawToDevice(plPipeline *pipe) override; void ICreateGeometry(); void IReleaseGeometry(); void EncodeDraw(MTL::RenderCommandEncoder *encoder); ~plMetalPlateManager(); -private: - struct plateVertexBuffer { + + private: + struct plateVertexBuffer + { hsPoint2 vertices[4]; hsPoint2 uv[4]; }; - MTL::Buffer *fVtxBuffer; - MTL::Buffer *idxBuffer; + MTL::Buffer *fVtxBuffer; + MTL::Buffer *idxBuffer; MTL::DepthStencilState *fDepthState; }; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.cpp index c0664feb24..f071d3f297 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.cpp @@ -39,17 +39,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "HeadSpin.h" - #include "plMetalShader.h" -#include "plSurface/plShader.h" - +#include "HeadSpin.h" #include "plMetalPipeline.h" +#include "plSurface/plShader.h" plMetalShader::plMetalShader(plShader* owner) -: fOwner(owner), - fPipe(nil) + : fOwner(owner), + fPipe(nil) { owner->SetDeviceRef(this); } @@ -63,7 +61,7 @@ plMetalShader::~plMetalShader() void plMetalShader::SetOwner(plShader* owner) { - if( owner != fOwner ) + if (owner != fOwner) { Release(); fOwner = owner; @@ -81,4 +79,3 @@ void plMetalShader::SetOwner(plShader* owner) return hr; }*/ - diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.h index 6706b095e2..7a8a6b8ba8 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalShader.h @@ -43,34 +43,35 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef plDXShader_inc #define plDXShader_inc -#include "plMetalDeviceRef.h" -#include #include +#include + +#include "plMetalDeviceRef.h" class plShader; class plMetalPipeline; class plMetalShader : public plMetalDeviceRef { -protected: - plShader* fOwner; + protected: + plShader* fOwner; //ST::string fErrorString; - plMetalPipeline* fPipe; - MTL::Function* fFunction; + plMetalPipeline* fPipe; + MTL::Function* fFunction; //HRESULT IOnError(HRESULT hr, const char* errStr); //void ISetError(const char* errStr) { fErrorString = errStr; } //virtual HRESULT ICreate(plDXPipeline* pipe) = 0; - virtual bool ISetConstants(plMetalPipeline* pipe) = 0; // On error, sets error string. + virtual bool ISetConstants(plMetalPipeline* pipe) = 0; // On error, sets error string. -public: + public: plMetalShader(plShader* owner); virtual ~plMetalShader(); //ST::string GetErrorString() const { return fErrorString; } - void SetOwner(plShader* owner); - MTL::Function* GetShader(plMetalPipeline* pipe) { return fFunction; }; + void SetOwner(plShader* owner); + MTL::Function* GetShader(plMetalPipeline* pipe) { return fFunction; }; }; -#endif // plDXShader_inc +#endif // plDXShader_inc diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.cpp index 7c899419ba..02d669c821 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.cpp @@ -54,23 +54,22 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "hsWindows.h" - #include "plMetalPipeline.h" #include "plPipeline/hsWinRef.h" - // Following number needs to be at least: 64 chars max in plTextFont drawn at any one time // * 4 primitives per char max (for bold text) // * 3 verts per primitive //const uint32_t kNumVertsInBuffer(32768); -const uint32_t kNumVertsInBuffer(4608); +const uint32_t kNumVertsInBuffer(4608); -uint32_t plMetalTextFont::fBufferCursor = 0; +uint32_t plMetalTextFont::fBufferCursor = 0; //// Constructor & Destructor ///////////////////////////////////////////////// -plMetalTextFont::plMetalTextFont( plPipeline *pipe, plMetalDevice* device ) : plTextFont( pipe ), fTexture() +plMetalTextFont::plMetalTextFont(plPipeline *pipe, plMetalDevice *device) : plTextFont(pipe), + fTexture() { fDevice = device; fPipeline = (plMetalPipeline *)pipe; @@ -84,41 +83,43 @@ plMetalTextFont::~plMetalTextFont() //// ICreateTexture /////////////////////////////////////////////////////////// -void plMetalTextFont::ICreateTexture( uint16_t *data ) +void plMetalTextFont::ICreateTexture(uint16_t *data) { printf("Create texture\n"); - + MTL::TextureDescriptor *descriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatRGBA8Unorm, fTextureWidth, fTextureHeight, false); - + fTexture->release(); fTexture = fDevice->fMetalDevice->newTexture(descriptor); fTexture->setLabel(NS::MakeConstantString("Font texture")); - - struct InDataValues { - uint8_t a: 4; - uint8_t r: 4; - uint8_t g: 4; - uint8_t b: 4; + + struct InDataValues + { + uint8_t a : 4; + uint8_t r : 4; + uint8_t g : 4; + uint8_t b : 4; }; - - struct OutDataValues { + + struct OutDataValues + { uint8_t r; uint8_t g; uint8_t b; uint8_t a; }; - + uint32_t *outData = new uint32_t[fTextureWidth * fTextureHeight]; - for(int i = 0; i < fTextureWidth * fTextureHeight; i++) { - InDataValues *in = (InDataValues *)(data + i); + for (int i = 0; i < fTextureWidth * fTextureHeight; i++) { + InDataValues *in = (InDataValues *)(data + i); OutDataValues *out = (OutDataValues *)(outData + i); - + out->r = in->r * 255; out->b = in->b * 255; out->g = in->g * 255; out->a = in->a * 255; } - + fTexture->replaceRegion(MTL::Region(0, 0, fTextureWidth, fTextureHeight), 0, outData, 4 * fTextureWidth); delete[] outData; /* @@ -142,19 +143,19 @@ void plMetalTextFont::ICreateTexture( uint16_t *data ) */ } -void plMetalTextFont::CreateShared(plMetalDevice* device) +void plMetalTextFont::CreateShared(plMetalDevice *device) { } -void plMetalTextFont::ReleaseShared(MTL::Device* device) +void plMetalTextFont::ReleaseShared(MTL::Device *device) { } //// IInitStateBlocks ///////////////////////////////////////////////////////// -void plMetalTextFont::IInitStateBlocks() +void plMetalTextFont::IInitStateBlocks() { -/* + /* for( int i = 0; i < 2; i++ ) { fDevice->BeginStateBlock(); @@ -203,34 +204,34 @@ void plMetalTextFont::IInitStateBlocks() //// DestroyObjects /////////////////////////////////////////////////////////// -void plMetalTextFont::DestroyObjects() +void plMetalTextFont::DestroyObjects() { fInitialized = false; } //// IDrawPrimitive /////////////////////////////////////////////////////////// -void plMetalTextFont::IDrawPrimitive( uint32_t count, plFontVertex *array ) +void plMetalTextFont::IDrawPrimitive(uint32_t count, plFontVertex *array) { - plFontVertex *v; - - plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalTextFontPipelineState(fDevice).GetRenderPipelineState(); - + plFontVertex *v; + + plMetalDevice::plMetalLinkedPipeline *linkedPipeline = plMetalTextFontPipelineState(fDevice).GetRenderPipelineState(); + fPipeline->fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(linkedPipeline->pipelineState); - const uint maxCount = 4096/(sizeof(plFontVertex) * 3); - uint drawm = 0; - while(count > 0) { + const uint maxCount = 4096 / (sizeof(plFontVertex) * 3); + uint drawm = 0; + while (count > 0) { uint drawCount = MIN(maxCount, count); - fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(array + (drawm * 3), drawCount * 3 * sizeof( plFontVertex ), 0); - + fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(array + (drawm * 3), drawCount * 3 * sizeof(plFontVertex), 0); + fPipeline->fDevice.CurrentRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), drawCount * 3); - + count -= drawCount; drawm += drawCount; } //if( !fBuffer ) - // return; + // return; /// Lock the buffer and write to it /*if( fBufferCursor && (fBufferCursor + count * 3 < kNumVertsInBuffer) ) @@ -270,21 +271,21 @@ void plMetalTextFont::IDrawPrimitive( uint32_t count, plFontVertex *array ) //// IDrawLines /////////////////////////////////////////////////////////////// -void plMetalTextFont::IDrawLines( uint32_t count, plFontVertex *array ) +void plMetalTextFont::IDrawLines(uint32_t count, plFontVertex *array) { - plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalTextFontPipelineState(fDevice).GetRenderPipelineState(); - + plMetalDevice::plMetalLinkedPipeline *linkedPipeline = plMetalTextFontPipelineState(fDevice).GetRenderPipelineState(); + fPipeline->fDevice.CurrentRenderCommandEncoder()->setRenderPipelineState(linkedPipeline->pipelineState); - fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(array, count * 2 * sizeof( plFontVertex ), 0); - + fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(array, count * 2 * sizeof(plFontVertex), 0); + matrix_float4x4 mat = matrix_identity_float4x4; mat.columns[0][0] = 2.0f / (float)fPipe->Width(); mat.columns[1][1] = -2.0f / (float)fPipe->Height(); mat.columns[3][0] = -1.0; mat.columns[3][1] = 1.0; - fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&mat, sizeof( matrix_float4x4 ), 1); + fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&mat, sizeof(matrix_float4x4), 1); fPipeline->fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(fTexture, 0); - + fPipeline->fDevice.CurrentRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeLine, NS::UInteger(0), count * 2); /*if( !fBuffer ) return; @@ -301,7 +302,7 @@ void plMetalTextFont::IDrawLines( uint32_t count, plFontVertex *array ) //// FlushDraws /////////////////////////////////////////////////////////////// // Flushes out and finishes any drawing left to be done. -void plMetalTextFont::FlushDraws() +void plMetalTextFont::FlushDraws() { /*if( !fBuffer ) return; @@ -318,15 +319,14 @@ void plMetalTextFont::FlushDraws() //// SaveStates /////////////////////////////////////////////////////////////// -void plMetalTextFont::SaveStates() +void plMetalTextFont::SaveStates() { - matrix_float4x4 mat = matrix_identity_float4x4; mat.columns[0][0] = 2.0f / (float)fPipe->Width(); mat.columns[1][1] = -2.0f / (float)fPipe->Height(); mat.columns[3][0] = -1.0; mat.columns[3][1] = 1.0; - fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&mat, sizeof( matrix_float4x4 ), 1); + fPipeline->fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&mat, sizeof(matrix_float4x4), 1); fPipeline->fDevice.CurrentRenderCommandEncoder()->setFragmentTexture(fTexture, 0); /*if( !fInitialized ) IInitObjects(); @@ -353,7 +353,7 @@ void plMetalTextFont::SaveStates() //// RestoreStates //////////////////////////////////////////////////////////// -void plMetalTextFont::RestoreStates() +void plMetalTextFont::RestoreStates() { /*if (fOldStateBlock) fOldStateBlock->Apply(); @@ -362,38 +362,43 @@ void plMetalTextFont::RestoreStates() fDevice->SetTransform( D3DTS_TEXTURE0, &d3dIdentityMatrix );*/ } - - -bool plMetalTextFontPipelineState::IsEqual(const plMetalPipelineState &p) const { +bool plMetalTextFontPipelineState::IsEqual(const plMetalPipelineState &p) const +{ return true; } -plMetalPipelineState *plMetalTextFontPipelineState::Clone() { +plMetalPipelineState *plMetalTextFontPipelineState::Clone() +{ return new plMetalTextFontPipelineState(fDevice); } -const MTL::Function *plMetalTextFontPipelineState::GetVertexFunction(MTL::Library *library) { +const MTL::Function *plMetalTextFontPipelineState::GetVertexFunction(MTL::Library *library) +{ return library->newFunction(NS::MakeConstantString("textFontVertexShader")); } -const MTL::Function *plMetalTextFontPipelineState::GetFragmentFunction(MTL::Library *library) { +const MTL::Function *plMetalTextFontPipelineState::GetFragmentFunction(MTL::Library *library) +{ return library->newFunction(NS::MakeConstantString("textFontFragmentShader")); } -const NS::String *plMetalTextFontPipelineState::GetDescription() { +const NS::String *plMetalTextFontPipelineState::GetDescription() +{ return NS::MakeConstantString("Font Rendering"); } -void plMetalTextFontPipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) { - +void plMetalTextFontPipelineState::ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) +{ descriptor->setSourceRGBBlendFactor(MTL::BlendFactorSourceAlpha); descriptor->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha); } -void plMetalTextFontPipelineState::ConfigureVertexDescriptor(MTL::VertexDescriptor *vertexDescriptor) { +void plMetalTextFontPipelineState::ConfigureVertexDescriptor(MTL::VertexDescriptor *vertexDescriptor) +{ return; } -void plMetalTextFontPipelineState::GetFunctionConstants(MTL::FunctionConstantValues *) const { +void plMetalTextFontPipelineState::GetFunctionConstants(MTL::FunctionConstantValues *) const +{ return; } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.h index 35fa5dbcf8..ef88a7e76a 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalTextFont.h @@ -42,11 +42,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef _plDXTextFont_h #define _plDXTextFont_h -#include "plPipeline/plTextFont.h" -#include "plMetalPipeline.h" -#include "plMetalPipelineState.h" #include +#include "plMetalPipeline.h" +#include "plMetalPipelineState.h" +#include "plPipeline/plTextFont.h" //// plDXTextFont Class Definition /////////////////////////////////////////// @@ -55,51 +55,48 @@ class plMetalDevice; class plMetalTextFontPipelineState : public plMetalPipelineState { -public: - plMetalTextFontPipelineState(plMetalDevice* device): plMetalPipelineState(device) { }; - virtual bool IsEqual(const plMetalPipelineState &p) const override; - virtual uint16_t GetID() const override { return 6; }; + public: + plMetalTextFontPipelineState(plMetalDevice* device) : plMetalPipelineState(device){}; + virtual bool IsEqual(const plMetalPipelineState& p) const override; + virtual uint16_t GetID() const override { return 6; }; virtual plMetalPipelineState* Clone() override; virtual const MTL::Function* GetVertexFunction(MTL::Library* library) override; virtual const MTL::Function* GetFragmentFunction(MTL::Library* library) override; virtual const NS::String* GetDescription() override; - - void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor *descriptor) override; - - void ConfigureVertexDescriptor(MTL::VertexDescriptor *vertexDescriptor) override; - - void GetFunctionConstants(MTL::FunctionConstantValues *) const override; - + + void ConfigureBlend(MTL::RenderPipelineColorAttachmentDescriptor* descriptor) override; + + void ConfigureVertexDescriptor(MTL::VertexDescriptor* vertexDescriptor) override; + + void GetFunctionConstants(MTL::FunctionConstantValues*) const override; }; class plMetalTextFont : public plTextFont { -protected: - static uint32_t fBufferCursor; - - void ICreateTexture(uint16_t *data) override; - void IInitStateBlocks() override; - void IDrawPrimitive(uint32_t count, plFontVertex *array) override; - void IDrawLines(uint32_t count, plFontVertex *array) override; - - MTL::Texture* fTexture; - plMetalDevice* fDevice; - + protected: + static uint32_t fBufferCursor; + + void ICreateTexture(uint16_t* data) override; + void IInitStateBlocks() override; + void IDrawPrimitive(uint32_t count, plFontVertex* array) override; + void IDrawLines(uint32_t count, plFontVertex* array) override; + + MTL::Texture* fTexture; + plMetalDevice* fDevice; + plMetalPipeline* fPipeline; -public: - plMetalTextFont( plPipeline *pipe, plMetalDevice *device ); + public: + plMetalTextFont(plPipeline* pipe, plMetalDevice* device); ~plMetalTextFont(); - static void CreateShared(plMetalDevice* device); - static void ReleaseShared(MTL::Device* device); + static void CreateShared(plMetalDevice* device); + static void ReleaseShared(MTL::Device* device); - void FlushDraws() override; - void SaveStates() override; - void RestoreStates() override; - void DestroyObjects() override; + void FlushDraws() override; + void SaveStates() override; + void RestoreStates() override; + void DestroyObjects() override; }; - -#endif // _plDXTextFont_h - +#endif // _plDXTextFont_h diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.cpp index 0f9a94c507..cde50d24be 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.cpp @@ -39,20 +39,18 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "HeadSpin.h" -#include "hsWindows.h" - -#include - #include "plMetalVertexShader.h" -#include "plSurface/plShader.h" +#include +#include "HeadSpin.h" +#include "hsWindows.h" #include "plDrawable/plGBufferGroup.h" #include "plMetalPipeline.h" +#include "plSurface/plShader.h" plMetalVertexShader::plMetalVertexShader(plShader* owner) -: plMetalShader(owner) + : plMetalShader(owner) { } @@ -70,12 +68,11 @@ void plMetalVertexShader::Release() bool plMetalVertexShader::ISetConstants(plMetalPipeline* pipe) { - if( fOwner->GetNumConsts() ) + if (fOwner->GetNumConsts()) { - float *ptr = (float *)fOwner->GetConstBasePtr(); - pipe->GetMetalDevice()->CurrentRenderCommandEncoder()->setVertexBytes(ptr, fOwner->GetNumConsts() * sizeof(float) * 4, VertexShaderArgumentMaterialShaderUniforms); + float* ptr = (float*)fOwner->GetConstBasePtr(); + pipe->GetMetalDevice()->CurrentRenderCommandEncoder()->setVertexBytes(ptr, fOwner->GetNumConsts() * sizeof(float) * 4, VertexShaderArgumentMaterialShaderUniforms); } return true; } - diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.h index 3a096d097a..1ea8e4bdfb 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalVertexShader.h @@ -50,17 +50,15 @@ class plMetalPipeline; class plMetalVertexShader : public plMetalShader { -protected: - - -public: - virtual bool ISetConstants(plMetalPipeline* pipe); // On error, sets error string. + protected: + public: + virtual bool ISetConstants(plMetalPipeline* pipe); // On error, sets error string. plMetalVertexShader(plShader* owner); virtual ~plMetalVertexShader(); - virtual void Release(); - void Link(plMetalVertexShader** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } - plMetalVertexShader* GetNext() { return (plMetalVertexShader*)fNext; } + virtual void Release(); + void Link(plMetalVertexShader** back) { plMetalDeviceRef::Link((plMetalDeviceRef**)back); } + plMetalVertexShader* GetNext() { return (plMetalVertexShader*)fNext; } }; -#endif // plMetalVertexShader_inc +#endif // plMetalVertexShader_inc