mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 20:54:46 +00:00
Fixed up forward IBL Reimplemented old forward light shader code as a baseline so it can be updated to new PBR math
290 lines
9.3 KiB
C++
290 lines
9.3 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platform/platform.h"
|
|
#include "gfx/genericConstBuffer.h"
|
|
|
|
#include "platform/profiler.h"
|
|
#include "core/stream/stream.h"
|
|
|
|
|
|
GenericConstBufferLayout::GenericConstBufferLayout()
|
|
{
|
|
VECTOR_SET_ASSOCIATION( mParams );
|
|
|
|
mBufferSize = 0;
|
|
mCurrentIndex = 0;
|
|
mTimesCleared = 0;
|
|
}
|
|
|
|
void GenericConstBufferLayout::addParameter(const String& name, const GFXShaderConstType constType, const U32 offset, const U32 size, const U32 arraySize, const U32 alignValue)
|
|
{
|
|
#ifdef TORQUE_DEBUG
|
|
// Make sure we don't have overlapping parameters
|
|
S32 start = offset;
|
|
S32 end = offset + size;
|
|
for (Params::iterator i = mParams.begin(); i != mParams.end(); i++)
|
|
{
|
|
const ParamDesc& dp = *i;
|
|
S32 pstart = dp.offset;
|
|
S32 pend = pstart + dp.size;
|
|
pstart -= start;
|
|
pend -= end;
|
|
// This is like a minkowski sum for two line segments, if the newly formed line contains
|
|
// the origin, then they intersect
|
|
bool intersect = ((pstart >= 0 && 0 >= pend) || ((pend >= 0 && 0 >= pstart)));
|
|
AssertFatal(!intersect, "Overlapping shader parameter!");
|
|
}
|
|
#endif
|
|
ParamDesc desc;
|
|
desc.name = name;
|
|
desc.constType = constType;
|
|
desc.offset = offset;
|
|
desc.size = size;
|
|
desc.arraySize = arraySize;
|
|
desc.alignValue = alignValue;
|
|
desc.index = mCurrentIndex++;
|
|
mParams.push_back(desc);
|
|
mBufferSize = getMax(desc.offset + desc.size, mBufferSize);
|
|
AssertFatal(mBufferSize, "Empty constant buffer!");
|
|
}
|
|
|
|
bool GenericConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer)
|
|
{
|
|
PROFILE_SCOPE(GenericConstBufferLayout_set);
|
|
|
|
// Shader compilers like to optimize float4x4 uniforms into float3x3s.
|
|
// So long as the real paramater is a matrix of-some-type and the data
|
|
// passed in is a MatrixF ( which is will be ), we DO NOT have a
|
|
// mismatched const type.
|
|
AssertFatal( pd.constType == constType ||
|
|
(
|
|
( pd.constType == GFXSCT_Float2x2 ||
|
|
pd.constType == GFXSCT_Float3x3 ||
|
|
pd.constType == GFXSCT_Float3x4 ||
|
|
pd.constType == GFXSCT_Float4x3 ||
|
|
pd.constType == GFXSCT_Float4x4 ) &&
|
|
( constType == GFXSCT_Float2x2 ||
|
|
constType == GFXSCT_Float3x3 ||
|
|
constType == GFXSCT_Float3x4 ||
|
|
constType == GFXSCT_Float4x3 ||
|
|
constType == GFXSCT_Float4x4 )
|
|
), "Mismatched const type!" );
|
|
|
|
// This "cute" bit of code allows us to support 2x3 and 3x3 matrices in shader constants but use our MatrixF class. Yes, a hack. -BTR
|
|
switch (pd.constType)
|
|
{
|
|
case GFXSCT_Float2x2 :
|
|
case GFXSCT_Float3x3 :
|
|
case GFXSCT_Float4x3 :
|
|
case GFXSCT_Float4x4 :
|
|
return setMatrix(pd, constType, size, data, basePointer);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
|
|
AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!");
|
|
|
|
// Ok, we only set data if it's different than the data we already have, this maybe more expensive than just setting the data, but
|
|
// we'll have to do some timings to see. For example, the lighting shader constants rarely change, but we can't assume that at the
|
|
// renderInstMgr level, but we can check down here. -BTR
|
|
if (dMemcmp(basePointer+pd.offset, data, size) != 0)
|
|
{
|
|
dMemcpy(basePointer+pd.offset, data, size);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool GenericConstBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer)
|
|
{
|
|
PROFILE_SCOPE(GenericConstBufferLayout_setMatrix);
|
|
|
|
// We're generic, so just copy the full MatrixF in
|
|
AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!");
|
|
|
|
// Matrices are an annoying case because of the alignment issues. There are alignment issues in the matrix itself, and then potential inter matrices alignment issues.
|
|
// So GL and DX will need to derive their own GenericConstBufferLayout classes and override this method to deal with that stuff. For GenericConstBuffer, copy the whole
|
|
// 4x4 matrix regardless of the target case.
|
|
|
|
if (dMemcmp(basePointer+pd.offset, data, size) != 0)
|
|
{
|
|
dMemcpy(basePointer+pd.offset, data, size);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GenericConstBufferLayout::getDesc(const String& name, ParamDesc& param) const
|
|
{
|
|
for (U32 i = 0; i < mParams.size(); i++)
|
|
{
|
|
if (mParams[i].name.equal(name))
|
|
{
|
|
param = mParams[i];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool GenericConstBufferLayout::getDesc(const U32 index, ParamDesc& param) const
|
|
{
|
|
if ( index < mParams.size() )
|
|
{
|
|
param = mParams[index];
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GenericConstBufferLayout::write(Stream* s)
|
|
{
|
|
// Write out the size of the ParamDesc structure as a sanity check.
|
|
if (!s->write((U32) sizeof(ParamDesc)))
|
|
return false;
|
|
// Next, write out the number of elements we've got.
|
|
if (!s->write(mParams.size()))
|
|
return false;
|
|
for (U32 i = 0; i < mParams.size(); i++)
|
|
{
|
|
s->write(mParams[i].name);
|
|
|
|
if (!s->write(mParams[i].offset))
|
|
return false;
|
|
if (!s->write(mParams[i].size))
|
|
return false;
|
|
U32 t = (U32) mParams[i].constType;
|
|
if (!s->write(t))
|
|
return false;
|
|
if (!s->write(mParams[i].arraySize))
|
|
return false;
|
|
if (!s->write(mParams[i].alignValue))
|
|
return false;
|
|
if (!s->write(mParams[i].index))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Load this layout from a stream
|
|
bool GenericConstBufferLayout::read(Stream* s)
|
|
{
|
|
U32 structSize;
|
|
if (!s->read(&structSize))
|
|
return false;
|
|
if (structSize != sizeof(ParamDesc))
|
|
{
|
|
AssertFatal(false, "Invalid shader layout structure size!");
|
|
return false;
|
|
}
|
|
U32 numParams;
|
|
if (!s->read(&numParams))
|
|
return false;
|
|
mParams.setSize(numParams);
|
|
mBufferSize = 0;
|
|
mCurrentIndex = 0;
|
|
for (U32 i = 0; i < mParams.size(); i++)
|
|
{
|
|
s->read(&mParams[i].name);
|
|
if (!s->read(&mParams[i].offset))
|
|
return false;
|
|
if (!s->read(&mParams[i].size))
|
|
return false;
|
|
U32 t;
|
|
if (!s->read(&t))
|
|
return false;
|
|
mParams[i].constType = (GFXShaderConstType) t;
|
|
if (!s->read(&mParams[i].arraySize))
|
|
return false;
|
|
if (!s->read(&mParams[i].alignValue))
|
|
return false;
|
|
if (!s->read(&mParams[i].index))
|
|
return false;
|
|
mBufferSize = getMax(mParams[i].offset + mParams[i].size, mBufferSize);
|
|
mCurrentIndex = getMax(mParams[i].index, mCurrentIndex);
|
|
}
|
|
mCurrentIndex++;
|
|
return true;
|
|
}
|
|
|
|
void GenericConstBufferLayout::clear()
|
|
{
|
|
mParams.clear();
|
|
mBufferSize = 0;
|
|
mCurrentIndex = 0;
|
|
mTimesCleared++;
|
|
}
|
|
|
|
|
|
GenericConstBuffer::GenericConstBuffer(GenericConstBufferLayout* layout)
|
|
: mLayout( layout ),
|
|
mBuffer( NULL ),
|
|
mDirtyStart( U32_MAX ),
|
|
mDirtyEnd( 0 )
|
|
{
|
|
if ( layout && layout->getBufferSize() > 0 )
|
|
{
|
|
mBuffer = new U8[mLayout->getBufferSize()];
|
|
|
|
// Always set a default value, that way our isEqual checks
|
|
// will work in release as well.
|
|
dMemset( mBuffer, 0xFFFF, mLayout->getBufferSize() );
|
|
|
|
#ifdef TORQUE_DEBUG
|
|
|
|
// Clear the debug assignment tracking.
|
|
mWasAssigned.setSize( layout->getParameterCount() );
|
|
dMemset( mWasAssigned.address(), 0, mWasAssigned.memSize() );
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
GenericConstBuffer::~GenericConstBuffer()
|
|
{
|
|
delete [] mBuffer;
|
|
}
|
|
|
|
#ifdef TORQUE_DEBUG
|
|
|
|
void GenericConstBuffer::assertUnassignedConstants( const char *shaderName )
|
|
{
|
|
for ( U32 i=0; i < mWasAssigned.size(); i++ )
|
|
{
|
|
if ( mWasAssigned[i] )
|
|
continue;
|
|
|
|
GenericConstBufferLayout::ParamDesc pd;
|
|
mLayout->getDesc( i, pd );
|
|
|
|
// Assert on the unassigned constant.
|
|
//AssertFatal( false, avar( "The '%s' shader constant in shader '%s' was unassigned!",
|
|
// pd.name.c_str(), shaderName ) );
|
|
}
|
|
}
|
|
|
|
#endif
|