genericConstBuffer.cpp
Engine/source/gfx/genericConstBuffer.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "gfx/genericConstBuffer.h" 26 27#include "platform/profiler.h" 28#include "core/stream/stream.h" 29 30 31GenericConstBufferLayout::GenericConstBufferLayout() 32{ 33 VECTOR_SET_ASSOCIATION( mParams ); 34 35 mBufferSize = 0; 36 mCurrentIndex = 0; 37 mTimesCleared = 0; 38} 39 40void GenericConstBufferLayout::addParameter(const String& name, const GFXShaderConstType constType, const U32 offset, const U32 size, const U32 arraySize, const U32 alignValue) 41{ 42#ifdef TORQUE_DEBUG 43 // Make sure we don't have overlapping parameters 44 S32 start = offset; 45 S32 end = offset + size; 46 for (Params::iterator i = mParams.begin(); i != mParams.end(); i++) 47 { 48 const ParamDesc& dp = *i; 49 S32 pstart = dp.offset; 50 S32 pend = pstart + dp.size; 51 pstart -= start; 52 pend -= end; 53 // This is like a minkowski sum for two line segments, if the newly formed line contains 54 // the origin, then they intersect 55 bool intersect = ((pstart >= 0 && 0 >= pend) || ((pend >= 0 && 0 >= pstart))); 56 AssertFatal(!intersect, "Overlapping shader parameter!"); 57 } 58#endif 59 ParamDesc desc; 60 desc.name = name; 61 desc.constType = constType; 62 desc.offset = offset; 63 desc.size = size; 64 desc.arraySize = arraySize; 65 desc.alignValue = alignValue; 66 desc.index = mCurrentIndex++; 67 mParams.push_back(desc); 68 mBufferSize = getMax(desc.offset + desc.size, mBufferSize); 69 AssertFatal(mBufferSize, "Empty constant buffer!"); 70} 71 72bool GenericConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer) 73{ 74 PROFILE_SCOPE(GenericConstBufferLayout_set); 75 76 // Shader compilers like to optimize float4x4 uniforms into float3x3s. 77 // So long as the real paramater is a matrix of-some-type and the data 78 // passed in is a MatrixF ( which is will be ), we DO NOT have a 79 // mismatched const type. 80 AssertFatal( pd.constType == constType || 81 ( 82 ( pd.constType == GFXSCT_Float2x2 || 83 pd.constType == GFXSCT_Float3x3 || 84 pd.constType == GFXSCT_Float3x4 || 85 pd.constType == GFXSCT_Float4x3 || 86 pd.constType == GFXSCT_Float4x4 ) && 87 ( constType == GFXSCT_Float2x2 || 88 constType == GFXSCT_Float3x3 || 89 constType == GFXSCT_Float3x4 || 90 constType == GFXSCT_Float4x3 || 91 constType == GFXSCT_Float4x4 ) 92 ), "Mismatched const type!" ); 93 94 // 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 95 switch (pd.constType) 96 { 97 case GFXSCT_Float2x2 : 98 case GFXSCT_Float3x3 : 99 case GFXSCT_Float4x3 : 100 case GFXSCT_Float4x4 : 101 return setMatrix(pd, constType, size, data, basePointer); 102 break; 103 default : 104 break; 105 } 106 107 AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); 108 109 // 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 110 // 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 111 // renderInstMgr level, but we can check down here. -BTR 112 if (dMemcmp(basePointer+pd.offset, data, size) != 0) 113 { 114 dMemcpy(basePointer+pd.offset, data, size); 115 return true; 116 } 117 return false; 118} 119 120bool GenericConstBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer) 121{ 122 PROFILE_SCOPE(GenericConstBufferLayout_setMatrix); 123 124 // We're generic, so just copy the full MatrixF in 125 AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); 126 127 // 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. 128 // 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 129 // 4x4 matrix regardless of the target case. 130 131 if (dMemcmp(basePointer+pd.offset, data, size) != 0) 132 { 133 dMemcpy(basePointer+pd.offset, data, size); 134 return true; 135 } 136 137 return false; 138} 139 140bool GenericConstBufferLayout::getDesc(const String& name, ParamDesc& param) const 141{ 142 for (U32 i = 0; i < mParams.size(); i++) 143 { 144 if (mParams[i].name.equal(name)) 145 { 146 param = mParams[i]; 147 return true; 148 } 149 } 150 return false; 151} 152 153bool GenericConstBufferLayout::getDesc(const U32 index, ParamDesc& param) const 154{ 155 if ( index < mParams.size() ) 156 { 157 param = mParams[index]; 158 return true; 159 } 160 161 return false; 162} 163 164bool GenericConstBufferLayout::write(Stream* s) 165{ 166 // Write out the size of the ParamDesc structure as a sanity check. 167 if (!s->write((U32) sizeof(ParamDesc))) 168 return false; 169 // Next, write out the number of elements we've got. 170 if (!s->write(mParams.size())) 171 return false; 172 for (U32 i = 0; i < mParams.size(); i++) 173 { 174 s->write(mParams[i].name); 175 176 if (!s->write(mParams[i].offset)) 177 return false; 178 if (!s->write(mParams[i].size)) 179 return false; 180 U32 t = (U32) mParams[i].constType; 181 if (!s->write(t)) 182 return false; 183 if (!s->write(mParams[i].arraySize)) 184 return false; 185 if (!s->write(mParams[i].alignValue)) 186 return false; 187 if (!s->write(mParams[i].index)) 188 return false; 189 } 190 return true; 191} 192 193/// Load this layout from a stream 194bool GenericConstBufferLayout::read(Stream* s) 195{ 196 U32 structSize; 197 if (!s->read(&structSize)) 198 return false; 199 if (structSize != sizeof(ParamDesc)) 200 { 201 AssertFatal(false, "Invalid shader layout structure size!"); 202 return false; 203 } 204 U32 numParams; 205 if (!s->read(&numParams)) 206 return false; 207 mParams.setSize(numParams); 208 mBufferSize = 0; 209 mCurrentIndex = 0; 210 for (U32 i = 0; i < mParams.size(); i++) 211 { 212 s->read(&mParams[i].name); 213 if (!s->read(&mParams[i].offset)) 214 return false; 215 if (!s->read(&mParams[i].size)) 216 return false; 217 U32 t; 218 if (!s->read(&t)) 219 return false; 220 mParams[i].constType = (GFXShaderConstType) t; 221 if (!s->read(&mParams[i].arraySize)) 222 return false; 223 if (!s->read(&mParams[i].alignValue)) 224 return false; 225 if (!s->read(&mParams[i].index)) 226 return false; 227 mBufferSize = getMax(mParams[i].offset + mParams[i].size, mBufferSize); 228 mCurrentIndex = getMax(mParams[i].index, mCurrentIndex); 229 } 230 mCurrentIndex++; 231 return true; 232} 233 234void GenericConstBufferLayout::clear() 235{ 236 mParams.clear(); 237 mBufferSize = 0; 238 mCurrentIndex = 0; 239 mTimesCleared++; 240} 241 242 243GenericConstBuffer::GenericConstBuffer(GenericConstBufferLayout* layout) 244 : mLayout( layout ), 245 mBuffer( NULL ), 246 mDirtyStart( U32_MAX ), 247 mDirtyEnd( 0 ) 248{ 249 if ( layout && layout->getBufferSize() > 0 ) 250 { 251 mBuffer = new U8[mLayout->getBufferSize()]; 252 253 // Always set a default value, that way our isEqual checks 254 // will work in release as well. 255 dMemset( mBuffer, 0xFFFF, mLayout->getBufferSize() ); 256 257 #ifdef TORQUE_DEBUG 258 259 // Clear the debug assignment tracking. 260 mWasAssigned.setSize( layout->getParameterCount() ); 261 dMemset( mWasAssigned.address(), 0, mWasAssigned.memSize() ); 262 263 #endif 264 } 265} 266 267GenericConstBuffer::~GenericConstBuffer() 268{ 269 delete [] mBuffer; 270} 271 272#ifdef TORQUE_DEBUG 273 274void GenericConstBuffer::assertUnassignedConstants( const char *shaderName ) 275{ 276 for ( U32 i=0; i < mWasAssigned.size(); i++ ) 277 { 278 if ( mWasAssigned[i] ) 279 continue; 280 281 GenericConstBufferLayout::ParamDesc pd; 282 mLayout->getDesc( i, pd ); 283 284 // Assert on the unassigned constant. 285 //AssertFatal( false, avar( "The '%s' shader constant in shader '%s' was unassigned!", 286 // pd.name.c_str(), shaderName ) ); 287 } 288} 289 290#endif 291