Skip to content

Commit

Permalink
Allowing per pixel lighting to be turned on dynamically
Browse files Browse the repository at this point in the history
Also cleaning up some redundant state binding
  • Loading branch information
colincornaby committed Nov 27, 2024
1 parent 9dc283c commit 8ed728a
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 25 deletions.
22 changes: 22 additions & 0 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/ShaderSrc/ShaderTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ struct plMaterialLightingDescriptor
uint8_t specularSrc;

bool invertAlpha;

#ifndef __METAL_VERSION__
bool operator==(const plMaterialLightingDescriptor& rhs) const
{
return memcmp(this, &rhs, sizeof(plMaterialLightingDescriptor)) == 0;
}
#endif
};

struct VertexUniforms
Expand All @@ -206,6 +213,13 @@ struct VertexUniforms
float3 sampleLocation(size_t index, thread float3 *texCoords, const float4 normal, const float4 camPosition) constant;
half4 calcFog(float4 camPosition) constant;
#endif

#ifndef __METAL_VERSION__
bool operator==(const VertexUniforms& rhs) const
{
return memcmp(this, &rhs, sizeof(VertexUniforms)) == 0;
}
#endif
};
#ifndef __METAL_VERSION__
static_assert(std::is_trivial_v<VertexUniforms>, "VertexUniforms must be a trivial type!");
Expand All @@ -217,6 +231,14 @@ struct plMetalLights
{
uint8_t count;
plMetalShaderLightSource lampSources[kMetalMaxLightCount];

#ifndef __METAL_VERSION__
bool operator==(const plMetalLights& rhs) const
{
size_t lightSize = offsetof(plMetalLights, lampSources) + (sizeof(plMetalShaderLightSource) * count);
return rhs.count == count && memcmp(&rhs, this, lightSize ) == 0;
}
#endif
};
#ifndef __METAL_VERSION__
static_assert(std::is_trivial_v<plMetalLights>, "plMetalLights must be a trivial type!");
Expand Down
60 changes: 44 additions & 16 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,24 +149,15 @@ bool plRenderTriListFunc::RenderPrims() const
plProfile_IncCount(DrawTriangles, fNumTris);
plProfile_Inc(DrawPrimStatic);

// FIXME: Why is fCurrentRenderPassUniforms stored as a reference?
// FIXME: Replace memory comparison with dirty bool
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->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), VertexShaderArgumentMaterialLighting);
if (PLASMA_PER_PIXEL_LIGHTING)
{
fDevice->CurrentRenderCommandEncoder()->setFragmentBytes(&fDevice->fPipeline->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), FragmentShaderArgumentMaterialLighting);
}

plMetalLights* lights = &fDevice->fPipeline->fLights;
size_t lightSize = offsetof(plMetalLights, lampSources) + (sizeof(plMetalShaderLightSource) * lights->count);

if (PLASMA_PER_PIXEL_LIGHTING)
if ( !(fDevice->fPipeline->fState.fCurrentVertexUniforms.has_value() && fDevice->fPipeline->fState.fCurrentVertexUniforms == *fDevice->fPipeline->fCurrentRenderPassUniforms) )
{
fDevice->CurrentRenderCommandEncoder()->setFragmentBytes(lights, sizeof(plMetalLights), FragmentShaderArgumentLights);
} else {
fDevice->CurrentRenderCommandEncoder()->setVertexBytes(lights, sizeof(plMetalLights), VertexShaderArgumentLights);
fDevice->fPipeline->fState.fCurrentVertexUniforms = *fDevice->fPipeline->fCurrentRenderPassUniforms;
fDevice->CurrentRenderCommandEncoder()->setVertexBytes(fDevice->fPipeline->fCurrentRenderPassUniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms);
}

fDevice->CurrentRenderCommandEncoder()->drawIndexedPrimitives(MTL::PrimitiveTypeTriangle, fNumTris * 3, MTL::IndexTypeUInt16, fDevice->fCurrentIndexBuffer, (sizeof(uint16_t) * fIStart));
}

Expand Down Expand Up @@ -1220,6 +1211,7 @@ void plMetalPipeline::IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb,
uint32_t pass;
for (pass = 0; pass < mRef->GetNumPasses(); pass++) {
if (IHandleMaterialPass(material, pass, &span, vRef)) {
IBindLights();
render.RenderPrims();
}

Expand Down Expand Up @@ -1394,6 +1386,7 @@ void plMetalPipeline::IRenderProjectionEach(const plRenderPrimFunc& render, hsGM
IHandleMaterialPass(material, iPass, &span, vRef, false);

IScaleLight(0, true);
IBindLights();

// Do the render with projection.
render.RenderPrims();
Expand Down Expand Up @@ -1503,7 +1496,8 @@ void plMetalPipeline::IRenderAuxSpan(const plSpan& span, const plAuxSpan* aux)
fCurrentRenderPassMaterialLighting.emissiveSrc = 0.0;
fCurrentRenderPassMaterialLighting.specularSrc = 1.0;
}


IBindLights();
render.RenderPrims();
}
}
Expand Down Expand Up @@ -1680,6 +1674,8 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial* material, uint32_t pass,
preEncodeTransform,
postEncodeTransform);
}

fLightingPerPixel = fragmentShaderDescription.fUsePerPixelLighting = PLASMA_FORCE_PER_PIXEL_LIGHTING;

plMetalDevice::plMetalLinkedPipeline* linkedPipeline = plMetalMaterialPassPipelineState(&fDevice, vRef, fragmentShaderDescription).GetRenderPipelineState();
const MTL::RenderPipelineState* pipelineState = linkedPipeline->pipelineState;
Expand All @@ -1693,6 +1689,33 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial* material, uint32_t pass,
return true;
}

void plMetalPipeline::IBindLights()
{
size_t lightSize = offsetof(plMetalLights, lampSources) + (sizeof(plMetalShaderLightSource) * fLights.count);

// FIXME: These states should support dirtying instead of expense memcmps
if ( !(fState.fBoundLights.has_value() && fState.fBoundLights == fLights) )
{
fState.fBoundLights = fLights;
if (fLightingPerPixel)
{
fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&fLights, sizeof(plMetalLights), FragmentShaderArgumentLights);
} else {
fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&fLights, sizeof(plMetalLights), VertexShaderArgumentLights);
}
}

if ( !(fState.fBoundMaterialProperties.has_value() && fState.fBoundMaterialProperties == fCurrentRenderPassMaterialLighting) )
{
fState.fBoundMaterialProperties = fCurrentRenderPassMaterialLighting;
fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&fDevice.fPipeline->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), VertexShaderArgumentMaterialLighting);
if (fLightingPerPixel)
{
fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&fDevice.fPipeline->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), FragmentShaderArgumentMaterialLighting);
}
}
}

// ISetPipeConsts //////////////////////////////////////////////////////////////////
// A shader can request that the pipeline fill in certain constants that are indeterminate
// until the pipeline is about to render the object the shader is applied to. For example,
Expand Down Expand Up @@ -2519,6 +2542,8 @@ void plMetalPipeline::IDrawPlate(plPlate* plate)
// FIXME: Hacking the old texture drawing into the plate path
mRef->prepareTextures(fDevice.CurrentRenderCommandEncoder(), 0);

// FIXME: Plates don't participate properly in caching
fState.fCurrentVertexUniforms.reset();
fDevice.CurrentRenderCommandEncoder()->setVertexBytes(&uniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms);

pm->EncodeDraw(fDevice.CurrentRenderCommandEncoder());
Expand Down Expand Up @@ -4397,7 +4422,10 @@ void plMetalPipeline::plMetalPipelineCurrentState::Reset()
fCurrentPipelineState = nullptr;
fCurrentDepthStencilState = nullptr;
fCurrentVertexBuffer = nullptr;
fBoundLights.reset();
fBoundMaterialProperties.reset();
fCurrentCullMode.reset();
fCurrentVertexUniforms.reset();

for (auto& layer : layerStates) {
layer.clampFlag = hsGMatState::hsGMatClampFlags(-1);
Expand Down
14 changes: 10 additions & 4 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,10 @@ class plMetalPipeline : public pl3DPipeline<plMetalDevice>

void PushCurrentLightSources();
void PopCurrentLightSources();
void IBindLights();
plMetalLights fLights;
std::vector<plMetalLights*> fLightSourceStack;
bool fLightingPerPixel;

static plMetalEnumerate enumerator;

Expand All @@ -284,12 +286,16 @@ class plMetalPipeline : public pl3DPipeline<plMetalDevice>
hsGMatState::hsGMatClampFlags clampFlag;
} layerStates[8];

std::optional<MTL::CullMode> fCurrentCullMode;
const MTL::RenderPipelineState* fCurrentPipelineState;
MTL::Buffer* fCurrentVertexBuffer;
MTL::DepthStencilState* fCurrentDepthStencilState;
std::optional<MTL::CullMode> fCurrentCullMode;
const MTL::RenderPipelineState* fCurrentPipelineState;
MTL::Buffer* fCurrentVertexBuffer;
MTL::DepthStencilState* fCurrentDepthStencilState;
std::optional<plMetalLights> fBoundLights;
std::optional<plMaterialLightingDescriptor> fBoundMaterialProperties;
std::optional<VertexUniforms> fCurrentVertexUniforms;

void Reset();

} fState;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ void plMetalMaterialPassPipelineState::GetFunctionConstants(MTL::FunctionConstan
constants->setConstantValues(&fFragmentShaderDescription.fPassTypes, MTL::DataTypeUChar, NS::Range(FunctionConstantSources, 8));
constants->setConstantValues(&fFragmentShaderDescription.fBlendModes, MTL::DataTypeUInt, NS::Range(FunctionConstantBlendModes, 8));
constants->setConstantValues(&fFragmentShaderDescription.fMiscFlags, MTL::DataTypeUInt, NS::Range(FunctionConstantLayerFlags, 8));
bool perPixelLighting = PLASMA_PER_PIXEL_LIGHTING;
constants->setConstantValue(&perPixelLighting, MTL::DataTypeBool, FunctionConstantPerPixelLighting);
constants->setConstantValue(&fFragmentShaderDescription.fUsePerPixelLighting, MTL::DataTypeBool, FunctionConstantPerPixelLighting);
}

size_t plMetalMaterialPassPipelineState::GetHash() const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plMetalDevice.h"
#include "plSurface/plShaderTable.h"

#ifndef PLASMA_PER_PIXEL_LIGHTING
#define PLASMA_PER_PIXEL_LIGHTING 0
#ifndef PLASMA_FORCE_PER_PIXEL_LIGHTING
#define PLASMA_FORCE_PER_PIXEL_LIGHTING 0
#endif

enum plMetalPipelineType
Expand Down Expand Up @@ -151,12 +151,13 @@ struct plMetalFragmentShaderDescription
uint32_t fBlendModes[8];
uint32_t fMiscFlags[8];
uint8_t fNumLayers;
bool fUsePerPixelLighting;

size_t hash;

bool operator==(const plMetalFragmentShaderDescription& p) const
{
bool match = fNumLayers == p.fNumLayers && memcmp(fPassTypes, p.fPassTypes, sizeof(fPassTypes)) == 0 && memcmp(fBlendModes, p.fBlendModes, sizeof(fBlendModes)) == 0 && memcmp(fMiscFlags, p.fMiscFlags, sizeof(fMiscFlags)) == 0;
bool match = fNumLayers == p.fNumLayers && memcmp(fPassTypes, p.fPassTypes, sizeof(fPassTypes)) == 0 && memcmp(fBlendModes, p.fBlendModes, sizeof(fBlendModes)) == 0 && memcmp(fMiscFlags, p.fMiscFlags, sizeof(fMiscFlags)) == 0 && fUsePerPixelLighting == p.fUsePerPixelLighting;
return match;
}

Expand All @@ -173,6 +174,8 @@ struct plMetalFragmentShaderDescription

std::size_t value = std::hash<uint8_t>()(fNumLayers);
value ^= std::hash<uint8_t>()(fNumLayers);

value ^= std::hash<bool>()(fUsePerPixelLighting);

for (int i = 0; i < 8; i++) {
value ^= std::hash<uint32_t>()(fBlendModes[i]);
Expand Down

0 comments on commit 8ed728a

Please sign in to comment.