コード例 #1
0
ファイル: Material.cpp プロジェクト: foolhuang/Helium
/// @copydoc GameObject::BeginPrecacheResourceData()
bool Material::BeginPrecacheResourceData()
{
#if HELIUM_TOOLS
    // Convert shader options to variant indices if we just loaded a set of options.
    if( m_bLoadedOptions )
    {
        MemoryZero( m_persistentResourceData.m_shaderVariantIndices, sizeof( m_persistentResourceData.m_shaderVariantIndices ) );

        Shader* pShader = m_spShader;
        if( pShader )
        {
            const Shader::Options& rUserOptions = pShader->GetUserOptions();

            for( size_t shaderTypeIndex = 0;
                shaderTypeIndex < HELIUM_ARRAY_COUNT( m_persistentResourceData.m_shaderVariantIndices );
                ++shaderTypeIndex )
            {
                m_persistentResourceData.m_shaderVariantIndices[ shaderTypeIndex ] = static_cast< uint32_t >( rUserOptions.GetOptionSetIndex(
                    static_cast< RShader::EType >( shaderTypeIndex ),
                    m_userOptions.GetData(),
                    m_userOptions.GetSize() ) );
            }
        }

        m_userOptions.Clear();

        m_bLoadedOptions = false;
    }
#endif

    // Preload shader variant resources.
    Shader* pShader = m_spShader;
    if( !pShader )
    {
        for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_shaderVariants ); ++shaderTypeIndex )
        {
            HELIUM_ASSERT( IsInvalid( m_shaderVariantLoadIds[ shaderTypeIndex ] ) );
            m_shaderVariants[ shaderTypeIndex ].Release();
        }
    }
    else
    {
        for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_shaderVariants ); ++shaderTypeIndex )
        {
            HELIUM_ASSERT( IsInvalid( m_shaderVariantLoadIds[ shaderTypeIndex ] ) );
            m_shaderVariantLoadIds[ shaderTypeIndex ] = pShader->BeginLoadVariant(
                static_cast< RShader::EType >( shaderTypeIndex ),
                m_persistentResourceData.m_shaderVariantIndices[ shaderTypeIndex ] );
        }
    }

    // Preload the constant buffers for shader parameters.
    Renderer* pRenderer = Renderer::GetStaticInstance();
    if( pRenderer )
    {
        for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_constantBuffers ); ++shaderTypeIndex )
        {
            HELIUM_ASSERT( !m_constantBuffers[ shaderTypeIndex ] );
            HELIUM_ASSERT( IsInvalid( m_constantBufferLoadIds[ shaderTypeIndex ] ) );

            size_t bufferSize = GetSubDataSize( static_cast< uint32_t >( shaderTypeIndex ) );
            if( bufferSize == 0 )
            {
                continue;
            }

            RConstantBufferPtr spBuffer = pRenderer->CreateConstantBuffer(
                bufferSize,
                RENDERER_BUFFER_USAGE_STATIC );
            if( !spBuffer )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "Material::BeginPrecacheResourceData(): Failed to allocate constant buffer of %" )
                    TPRIuSZ TXT( " bytes for parameter usage for material \"%s\".\n" ) ),
                    bufferSize,
                    *GetPath().ToString() );

                continue;
            }

            void* pBufferData = spBuffer->Map();
            if( !pBufferData )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "Material::BeginPrecacheResourceData(): Failed to map constant buffer data for " )
                    TXT( "material \"%s\".\n" ) ),
                    *GetPath().ToString() );

                continue;
            }

            size_t loadId = BeginLoadSubData( pBufferData, static_cast< uint32_t >( shaderTypeIndex ) );
            if( IsInvalid( loadId ) )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "Material::BeginPrecacheResourceData(): Failed to begin loading resource sub-data %" )
                    TPRIuSZ TXT( " for material \"%s\".\n" ) ),
                    shaderTypeIndex,
                    *GetPath().ToString() );

                spBuffer->Unmap();

                continue;
            }

            m_constantBuffers[ shaderTypeIndex ] = spBuffer;
            m_constantBufferLoadIds[ shaderTypeIndex ] = loadId;
        }
    }

    return true;
}
コード例 #2
0
/// @copydoc ResourceHandler::CacheResource()
bool MaterialResourceHandler::CacheResource(
    AssetPreprocessor* pAssetPreprocessor,
    Resource* pResource,
    const String& /*rSourceFilePath*/ )
{
    HELIUM_ASSERT( pAssetPreprocessor );
    HELIUM_ASSERT( pResource );

    Material* pMaterial = Reflect::AssertCast< Material >( pResource );
    Shader* pShader = pMaterial->GetShader();
    bool failedToWriteASubdata = false;
    
    StrongPtr< Material::PersistentResourceData > resource_data( new Material::PersistentResourceData() );

    // Compute the shader variant indices from the user options selected in the material, as the array of indices in
    // the material is not yet initialized.
    //uint32_t shaderVariantIndices[ RShader::TYPE_MAX ];
    if( pShader )
    {
        const Shader::Options& rShaderUserOptions = pShader->GetUserOptions();
        const DynamicArray< Shader::SelectPair >& rMaterialUserOptions = pMaterial->GetUserOptions();

        for( size_t shaderTypeIndex = 0; shaderTypeIndex < RShader::TYPE_MAX; ++shaderTypeIndex )
        {
            size_t optionSetIndex = rShaderUserOptions.GetOptionSetIndex(
                static_cast< RShader::EType >( shaderTypeIndex ),
                rMaterialUserOptions.GetData(),
                rMaterialUserOptions.GetSize() );
            resource_data->m_shaderVariantIndices[ shaderTypeIndex ] = static_cast< uint32_t >( optionSetIndex );
        }
    }
    else
    {
        MemoryZero( resource_data->m_shaderVariantIndices, sizeof( resource_data->m_shaderVariantIndices ) );
    }

    size_t float1ParameterCount = pMaterial->GetFloat1ParameterCount();
    size_t float2ParameterCount = pMaterial->GetFloat2ParameterCount();
    size_t float3ParameterCount = pMaterial->GetFloat3ParameterCount();
    size_t float4ParameterCount = pMaterial->GetFloat4ParameterCount();

    Name parameterConstantBufferName = Material::GetParameterConstantBufferName();
    
    for( size_t platformIndex = 0; platformIndex < static_cast< size_t >( Cache::PLATFORM_MAX ); ++platformIndex )
    {
        PlatformPreprocessor* pPreprocessor = pAssetPreprocessor->GetPlatformPreprocessor(
            static_cast< Cache::EPlatform >( platformIndex ) );

        if( !pPreprocessor )
        {
            continue;
        }

        Resource::PreprocessedData& rPreprocessedData = pResource->GetPreprocessedData(
            static_cast< Cache::EPlatform >( platformIndex ) );
        SaveObjectToPersistentDataBuffer(resource_data.Get(), rPreprocessedData.persistentDataBuffer);
        rPreprocessedData.bLoaded = true;

        // Write out the parameter constant buffer data as the resource sub-data.
        size_t shaderProfileCount = pPreprocessor->GetShaderProfileCount();

        DynamicArray< DynamicArray< uint8_t > >& rSubDataBuffers = rPreprocessedData.subDataBuffers;
        rSubDataBuffers.Clear();
        rSubDataBuffers.Reserve( shaderProfileCount * RShader::TYPE_MAX );
        rSubDataBuffers.Resize( shaderProfileCount * RShader::TYPE_MAX );

        if( pShader )
        {
    //        deserializer.SetByteSwapping( bSwapBytes );

            for( size_t shaderTypeIndex = 0; shaderTypeIndex < RShader::TYPE_MAX; ++shaderTypeIndex )
            {
                RShader::EType shaderType = static_cast< RShader::EType >( shaderTypeIndex );
                size_t variantLoadId = pShader->BeginLoadVariant(
                    shaderType,
                    resource_data->m_shaderVariantIndices[ shaderTypeIndex ] );
                if( IsInvalid( variantLoadId ) )
                {
                    continue;
                }

                ShaderVariantPtr spVariant;
                while( !pShader->TryFinishLoadVariant( variantLoadId, spVariant ) )
                {
                }

                ShaderVariant* pVariant = spVariant;
                if( !pVariant )
                {
                    continue;
                }

                const Resource::PreprocessedData& rVariantData = pVariant->GetPreprocessedData(
                    static_cast< Cache::EPlatform >( platformIndex ) );
                HELIUM_ASSERT( rVariantData.bLoaded );

                const DynamicArray< DynamicArray< uint8_t > >& rVariantSubDataBuffers = rVariantData.subDataBuffers;
                size_t variantSubDataCount = rVariantSubDataBuffers.GetSize();
                HELIUM_ASSERT( variantSubDataCount != 0 );
                HELIUM_ASSERT( variantSubDataCount % shaderProfileCount == 0 );
                size_t systemOptionSetCount = variantSubDataCount / shaderProfileCount;

                for( size_t profileIndex = 0; profileIndex < shaderProfileCount; ++profileIndex )
                {
                    // Get the first option set of each profile
                    const DynamicArray< uint8_t >& rVariantSubData =
                        rVariantSubDataBuffers[ profileIndex * systemOptionSetCount ];

                    Reflect::ObjectPtr variantSubDataObjectPtr = 
                        Cache::ReadCacheObjectFromBuffer(rVariantSubData);

                    if (!variantSubDataObjectPtr.ReferencesObject())
                    {
                        HELIUM_TRACE(
                            TraceLevels::Error,
                            "MaterialResourceHandler: A shader variant subdata could not be read. (Option Set: %d Profile: %d)",
                            0,
                            profileIndex );

                        failedToWriteASubdata = true;
                    }
                    else if (!variantSubDataObjectPtr->IsA(Reflect::GetMetaClass<CompiledShaderData>()))
                    {
                        HELIUM_TRACE(
                            TraceLevels::Error,
                            "MaterialResourceHandler: A shader variant subdata was of an unexpected type. (Option Set: %d Profile: %d)\n",
                            0,
                            profileIndex );

                        failedToWriteASubdata = true;

                    }
                    else
                    {
                        CompiledShaderData &csd = *Reflect::AssertCast<CompiledShaderData>(variantSubDataObjectPtr.Get());
                        

                        size_t bufferCount = csd.constantBuffers.GetSize();
                        for( size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex )
                        {
                            const ShaderConstantBufferInfo& rBufferInfo = csd.constantBuffers[ bufferIndex ];
                            if( rBufferInfo.name != parameterConstantBufferName )
                            {
                                continue;
                            }

                            size_t bufferSize = rBufferInfo.size;

                            DynamicArray< uint8_t >& rMaterialSubData =
                                rSubDataBuffers[ profileIndex * RShader::TYPE_MAX + shaderTypeIndex ];
                            rMaterialSubData.Clear();
                            rMaterialSubData.Reserve( bufferSize );
                            rMaterialSubData.Add( 0, bufferSize );

                            DynamicMemoryStream memoryStream( &rMaterialSubData );
                            ByteSwappingStream byteSwapStream( &memoryStream );
                            Stream& rOutputStream = memoryStream;
                            //Stream& rOutputStream =
                            //    ( bSwapBytes
                            //    ? static_cast< Stream& >( byteSwapStream )
                            //    : static_cast< Stream& >( memoryStream ) );

                            const DynamicArray< ShaderConstantInfo >& rConstants = rBufferInfo.constants;
                            size_t constantCount = rConstants.GetSize();
                            for( size_t constantIndex = 0; constantIndex < constantCount; ++constantIndex )
                            {
                                const ShaderConstantInfo& rConstantInfo = rConstants[ constantIndex ];
                                Name constantName = rConstantInfo.name;

                                size_t parameterIndex;
                                for( parameterIndex = 0; parameterIndex < float1ParameterCount; ++parameterIndex )
                                {
                                    const Material::Float1Parameter& rParameter = pMaterial->GetFloat1Parameter(
                                        parameterIndex );
                                    if( rParameter.name == constantName )
                                    {
                                        rOutputStream.Seek( rConstantInfo.offset, SeekOrigins::Begin );
                                        rOutputStream.Write(
                                            &rParameter.value,
                                            sizeof( float32_t ),
                                            Min< size_t >( 1, rConstantInfo.size / sizeof( float32_t ) ) );

                                        break;
                                    }
                                }

                                if( parameterIndex >= float1ParameterCount )
                                {
                                    for( parameterIndex = 0; parameterIndex < float2ParameterCount; ++parameterIndex )
                                    {
                                        const Material::Float2Parameter& rParameter = pMaterial->GetFloat2Parameter(
                                            parameterIndex );
                                        if( rParameter.name == constantName )
                                        {
                                            rOutputStream.Seek( rConstantInfo.offset, SeekOrigins::Begin );
                                            rOutputStream.Write(
                                                &rParameter.value,
                                                sizeof( float32_t ),
                                                Min< size_t >( 2, rConstantInfo.size / sizeof( float32_t ) ) );

                                            break;
                                        }
                                    }

                                    if( parameterIndex >= float2ParameterCount )
                                    {
                                        for( parameterIndex = 0;
                                            parameterIndex < float3ParameterCount;
                                            ++parameterIndex )
                                        {
                                            const Material::Float3Parameter& rParameter = pMaterial->GetFloat3Parameter(
                                                parameterIndex );
                                            if( rParameter.name == constantName )
                                            {
                                                rOutputStream.Seek( rConstantInfo.offset, SeekOrigins::Begin );
                                                rOutputStream.Write(
                                                    &rParameter.value,
                                                    sizeof( float32_t ),
                                                    Min< size_t >( 3, rConstantInfo.size / sizeof( float32_t ) ) );

                                                break;
                                            }
                                        }

                                        if( parameterIndex >= float3ParameterCount )
                                        {
                                            for( parameterIndex = 0;
                                                parameterIndex < float4ParameterCount;
                                                ++parameterIndex )
                                            {
                                                const Material::Float4Parameter& rParameter =
                                                    pMaterial->GetFloat4Parameter( parameterIndex );
                                                if( rParameter.name == constantName )
                                                {
                                                    rOutputStream.Seek(
                                                        rConstantInfo.offset,
                                                        SeekOrigins::Begin );
                                                    rOutputStream.Write(
                                                        &rParameter.value,
                                                        sizeof( float32_t ),
                                                        Min< size_t >( 4, rConstantInfo.size / sizeof( float32_t ) ) );

                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            break;
                        }
                    }
                }
            }
        }
    }


    return !failedToWriteASubdata;
}
コード例 #3
0
/// Initialize all resources provided by this manager.
///
/// @see Cleanup(), PostConfigUpdate()
bool RenderResourceManager::Initialize()
{
	// Release any existing resources.
	Cleanup();

	// Get the renderer and graphics configuration.
	Renderer* pRenderer = Renderer::GetInstance();
	if ( !pRenderer )
	{
		return false;
	}

	Config* pConfig = Config::GetInstance();
	if ( !HELIUM_VERIFY( pConfig ) )
	{
		return false;
	}

	StrongPtr< GraphicsConfig > spGraphicsConfig( pConfig->GetConfigObject< GraphicsConfig >( Name( "GraphicsConfig" ) ) );
	if ( !spGraphicsConfig )
	{
		HELIUM_TRACE( TraceLevels::Error, "RenderResourceManager::Initialize(): Initialization failed; missing GraphicsConfig.\n" );
		return false;
	}

	// Create the standard rasterizer states.
	RRasterizerState::Description rasterizerStateDesc;

	rasterizerStateDesc.fillMode = RENDERER_FILL_MODE_SOLID;
	rasterizerStateDesc.cullMode = RENDERER_CULL_MODE_BACK;
	rasterizerStateDesc.winding = RENDERER_WINDING_CLOCKWISE;
	rasterizerStateDesc.depthBias = 0;
	rasterizerStateDesc.slopeScaledDepthBias = 0.0f;
	m_rasterizerStates[RASTERIZER_STATE_DEFAULT] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
	HELIUM_ASSERT( m_rasterizerStates[RASTERIZER_STATE_DEFAULT] );

	rasterizerStateDesc.cullMode = RENDERER_CULL_MODE_NONE;
	m_rasterizerStates[RASTERIZER_STATE_DOUBLE_SIDED] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
	HELIUM_ASSERT( m_rasterizerStates[RASTERIZER_STATE_DOUBLE_SIDED] );

	rasterizerStateDesc.depthBias = 1;
	rasterizerStateDesc.slopeScaledDepthBias = 2.0f;
	m_rasterizerStates[RASTERIZER_STATE_SHADOW_DEPTH] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
	HELIUM_ASSERT( m_rasterizerStates[RASTERIZER_STATE_SHADOW_DEPTH] );

	rasterizerStateDesc.depthBias = 0;
	rasterizerStateDesc.slopeScaledDepthBias = 0.0f;
	rasterizerStateDesc.fillMode = RENDERER_FILL_MODE_WIREFRAME;
	m_rasterizerStates[RASTERIZER_STATE_WIREFRAME_DOUBLE_SIDED] = pRenderer->CreateRasterizerState(
		rasterizerStateDesc );
	HELIUM_ASSERT( m_rasterizerStates[RASTERIZER_STATE_WIREFRAME_DOUBLE_SIDED] );

	rasterizerStateDesc.cullMode = RENDERER_CULL_MODE_BACK;
	m_rasterizerStates[RASTERIZER_STATE_WIREFRAME] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
	HELIUM_ASSERT( m_rasterizerStates[RASTERIZER_STATE_WIREFRAME] );

	// Create the standard blend states.
	RBlendState::Description blendStateDesc;

	blendStateDesc.bBlendEnable = false;
	m_blendStates[BLEND_STATE_OPAQUE] = pRenderer->CreateBlendState( blendStateDesc );
	HELIUM_ASSERT( m_blendStates[BLEND_STATE_OPAQUE] );

	blendStateDesc.colorWriteMask = 0;
	m_blendStates[BLEND_STATE_NO_COLOR] = pRenderer->CreateBlendState( blendStateDesc );
	HELIUM_ASSERT( m_blendStates[BLEND_STATE_NO_COLOR] );

	blendStateDesc.colorWriteMask = RENDERER_COLOR_WRITE_MASK_FLAG_ALL;
	blendStateDesc.bBlendEnable = true;

	blendStateDesc.sourceFactor = RENDERER_BLEND_FACTOR_SRC_ALPHA;
	blendStateDesc.destinationFactor = RENDERER_BLEND_FACTOR_INV_SRC_ALPHA;
	blendStateDesc.function = RENDERER_BLEND_FUNCTION_ADD;
	m_blendStates[BLEND_STATE_TRANSPARENT] = pRenderer->CreateBlendState( blendStateDesc );
	HELIUM_ASSERT( m_blendStates[BLEND_STATE_TRANSPARENT] );

	blendStateDesc.sourceFactor = RENDERER_BLEND_FACTOR_ONE;
	blendStateDesc.destinationFactor = RENDERER_BLEND_FACTOR_ONE;
	m_blendStates[BLEND_STATE_ADDITIVE] = pRenderer->CreateBlendState( blendStateDesc );
	HELIUM_ASSERT( m_blendStates[BLEND_STATE_ADDITIVE] );

	blendStateDesc.function = RENDERER_BLEND_FUNCTION_REVERSE_SUBTRACT;
	m_blendStates[BLEND_STATE_SUBTRACTIVE] = pRenderer->CreateBlendState( blendStateDesc );
	HELIUM_ASSERT( m_blendStates[BLEND_STATE_SUBTRACTIVE] );

	blendStateDesc.sourceFactor = RENDERER_BLEND_FACTOR_DEST_COLOR;
	blendStateDesc.destinationFactor = RENDERER_BLEND_FACTOR_ZERO;
	blendStateDesc.function = RENDERER_BLEND_FUNCTION_ADD;
	m_blendStates[BLEND_STATE_MODULATE] = pRenderer->CreateBlendState( blendStateDesc );
	HELIUM_ASSERT( m_blendStates[BLEND_STATE_MODULATE] );

	// Create the standard depth/stencil states.
	RDepthStencilState::Description depthStateDesc;

	depthStateDesc.stencilWriteMask = 0;
	depthStateDesc.bStencilTestEnable = false;

	depthStateDesc.depthFunction = RENDERER_COMPARE_FUNCTION_LESS_EQUAL;
	depthStateDesc.bDepthTestEnable = true;
	depthStateDesc.bDepthWriteEnable = true;
	m_depthStencilStates[DEPTH_STENCIL_STATE_DEFAULT] = pRenderer->CreateDepthStencilState( depthStateDesc );
	HELIUM_ASSERT( m_depthStencilStates[DEPTH_STENCIL_STATE_DEFAULT] );

	depthStateDesc.bDepthWriteEnable = false;
	m_depthStencilStates[DEPTH_STENCIL_STATE_TEST_ONLY] = pRenderer->CreateDepthStencilState( depthStateDesc );
	HELIUM_ASSERT( m_depthStencilStates[DEPTH_STENCIL_STATE_TEST_ONLY] );

	depthStateDesc.bDepthTestEnable = false;
	m_depthStencilStates[DEPTH_STENCIL_STATE_NONE] = pRenderer->CreateDepthStencilState( depthStateDesc );
	HELIUM_ASSERT( m_depthStencilStates[DEPTH_STENCIL_STATE_NONE] );

	// Create the standard sampler states that are not dependent on configuration settings.
	RSamplerState::Description samplerStateDesc;
	samplerStateDesc.filter = RENDERER_TEXTURE_FILTER_MIN_POINT_MAG_POINT_MIP_POINT;
	samplerStateDesc.addressModeW = RENDERER_TEXTURE_ADDRESS_MODE_CLAMP;
	samplerStateDesc.mipLodBias = 0;
	samplerStateDesc.maxAnisotropy = spGraphicsConfig->GetMaxAnisotropy();

	for ( size_t addressModeIndex = 0; addressModeIndex < RENDERER_TEXTURE_ADDRESS_MODE_MAX; ++addressModeIndex )
	{
		ERendererTextureAddressMode addressMode = static_cast<ERendererTextureAddressMode>( addressModeIndex );
		samplerStateDesc.addressModeU = addressMode;
		samplerStateDesc.addressModeV = addressMode;
		samplerStateDesc.addressModeW = addressMode;

		m_samplerStates[TEXTURE_FILTER_POINT][addressModeIndex] = pRenderer->CreateSamplerState( samplerStateDesc );
		HELIUM_ASSERT( m_samplerStates[TEXTURE_FILTER_POINT][addressModeIndex] );
	}

	// Create the standard set of mesh vertex descriptions.
	RVertexDescription::Element vertexElements[6];

	vertexElements[0].type = RENDERER_VERTEX_DATA_TYPE_FLOAT32_3;
	vertexElements[0].semantic = RENDERER_VERTEX_SEMANTIC_POSITION;
	vertexElements[0].semanticIndex = 0;
	vertexElements[0].bufferIndex = 0;

	vertexElements[1].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[1].semantic = RENDERER_VERTEX_SEMANTIC_COLOR;
	vertexElements[1].semanticIndex = 0;
	vertexElements[1].bufferIndex = 0;

	vertexElements[2].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
	vertexElements[2].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
	vertexElements[2].semanticIndex = 0;
	vertexElements[2].bufferIndex = 0;

	vertexElements[3].type = RENDERER_VERTEX_DATA_TYPE_FLOAT32_2;
	vertexElements[3].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
	vertexElements[3].semanticIndex = 1;
	vertexElements[3].bufferIndex = 0;

	m_spSimpleVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 2 );
	HELIUM_ASSERT( m_spSimpleVertexDescription );

	m_spSimpleTexturedVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 3 );
	HELIUM_ASSERT( m_spSimpleTexturedVertexDescription );

	m_spProjectedVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 4 );
	HELIUM_ASSERT( m_spProjectedVertexDescription );

	vertexElements[1].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[1].semantic = RENDERER_VERTEX_SEMANTIC_NORMAL;
	vertexElements[1].semanticIndex = 0;
	vertexElements[1].bufferIndex = 0;

	vertexElements[2].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[2].semantic = RENDERER_VERTEX_SEMANTIC_TANGENT;
	vertexElements[2].semanticIndex = 0;
	vertexElements[2].bufferIndex = 0;

	vertexElements[3].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[3].semantic = RENDERER_VERTEX_SEMANTIC_COLOR;
	vertexElements[3].semanticIndex = 0;
	vertexElements[3].bufferIndex = 0;

	vertexElements[4].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
	vertexElements[4].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
	vertexElements[4].semanticIndex = 0;
	vertexElements[4].bufferIndex = 0;

	vertexElements[5].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
	vertexElements[5].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
	vertexElements[5].semanticIndex = 1;
	vertexElements[5].bufferIndex = 0;

	m_staticMeshVertexDescriptions[0] = pRenderer->CreateVertexDescription( vertexElements, 5 );
	HELIUM_ASSERT( m_staticMeshVertexDescriptions[0] );

	m_staticMeshVertexDescriptions[1] = pRenderer->CreateVertexDescription( vertexElements, 6 );
	HELIUM_ASSERT( m_staticMeshVertexDescriptions[1] );

	vertexElements[1].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[1].semantic = RENDERER_VERTEX_SEMANTIC_BLENDWEIGHT;
	vertexElements[1].semanticIndex = 0;
	vertexElements[1].bufferIndex = 0;

	vertexElements[2].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4;
	vertexElements[2].semantic = RENDERER_VERTEX_SEMANTIC_BLENDINDICES;
	vertexElements[2].semanticIndex = 0;
	vertexElements[2].bufferIndex = 0;

	vertexElements[3].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[3].semantic = RENDERER_VERTEX_SEMANTIC_NORMAL;
	vertexElements[3].semanticIndex = 0;
	vertexElements[3].bufferIndex = 0;

	vertexElements[4].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[4].semantic = RENDERER_VERTEX_SEMANTIC_TANGENT;
	vertexElements[4].semanticIndex = 0;
	vertexElements[4].bufferIndex = 0;

	vertexElements[5].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
	vertexElements[5].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
	vertexElements[5].semanticIndex = 0;
	vertexElements[5].bufferIndex = 0;

	m_spSkinnedMeshVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 6 );
	HELIUM_ASSERT( m_spSkinnedMeshVertexDescription );

	vertexElements[0].type = RENDERER_VERTEX_DATA_TYPE_FLOAT32_2;
	vertexElements[0].semantic = RENDERER_VERTEX_SEMANTIC_POSITION;
	vertexElements[0].semanticIndex = 0;
	vertexElements[0].bufferIndex = 0;

	vertexElements[1].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
	vertexElements[1].semantic = RENDERER_VERTEX_SEMANTIC_COLOR;
	vertexElements[1].semanticIndex = 0;
	vertexElements[1].bufferIndex = 0;

	vertexElements[2].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
	vertexElements[2].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
	vertexElements[2].semanticIndex = 0;
	vertexElements[2].bufferIndex = 0;

	m_spScreenVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 3 );
	HELIUM_ASSERT( m_spScreenVertexDescription );

	// Create configuration-dependent render resources.
	PostConfigUpdate();

	// Attempt to load the depth-only pre-pass shader.
	// TODO: XXX TMC: Migrate to a more data-driven solution.
	AssetLoader* pAssetLoader = AssetLoader::GetInstance();
	HELIUM_ASSERT( pAssetLoader );

#ifdef HELIUM_DIRECT3D

	AssetPath prePassShaderPath;
	HELIUM_VERIFY( prePassShaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "PrePass.hlsl" ) );

	AssetPtr spPrePassShader;
	HELIUM_VERIFY( pAssetLoader->LoadObject( prePassShaderPath, spPrePassShader ) );

	Shader* pPrePassShader = Reflect::SafeCast< Shader >( spPrePassShader.Get() );
	if ( HELIUM_VERIFY( pPrePassShader ) )
	{
		size_t loadId = pPrePassShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pPrePassShader->TryFinishLoadVariant( loadId, m_spPrePassVertexShader ) )
			{
				pAssetLoader->Tick();
			}
		}
	}

	// Attempt to load the simple world-space, simple screen-space, and screen-space text shaders.
	// TODO: XXX TMC: Migrate to a more data-driven solution.
	AssetPath shaderPath;
	HELIUM_VERIFY( shaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "Simple.hlsl" ) );

	AssetPtr spShader;
	HELIUM_VERIFY( pAssetLoader->LoadObject( shaderPath, spShader ) );

	Shader* pShader = Reflect::SafeCast< Shader >( spShader.Get() );
	if ( HELIUM_VERIFY( pShader ) )
	{
		size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleWorldSpaceVertexShader ) )
			{
				pAssetLoader->Tick();
			}
		}

		loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleWorldSpacePixelShader ) )
			{
				pAssetLoader->Tick();
			}
		}
	}

	HELIUM_VERIFY( shaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "ScreenSpaceTexture.hlsl" ) );
	HELIUM_VERIFY( pAssetLoader->LoadObject( shaderPath, spShader ) );
	pShader = Reflect::SafeCast< Shader >( spShader.Get() );
	if ( HELIUM_VERIFY( pShader ) )
	{
		size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleScreenSpaceVertexShader ) )
			{
				pAssetLoader->Tick();
			}
		}

		loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleScreenSpacePixelShader ) )
			{
				pAssetLoader->Tick();
			}
		}
	}

	HELIUM_VERIFY( shaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "ScreenText.hlsl" ) );
	HELIUM_VERIFY( pAssetLoader->LoadObject( shaderPath, spShader ) );
	pShader = Reflect::SafeCast< Shader >( spShader.Get() );
	if ( HELIUM_VERIFY( pShader ) )
	{
		size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pShader->TryFinishLoadVariant( loadId, m_spScreenTextVertexShader ) )
			{
				pAssetLoader->Tick();
			}
		}

		loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 );
		HELIUM_ASSERT( IsValid( loadId ) );
		if ( IsValid( loadId ) )
		{
			while ( !pShader->TryFinishLoadVariant( loadId, m_spScreenTextPixelShader ) )
			{
				pAssetLoader->Tick();
			}
		}
	}

	// Attempt to load the debug fonts.
	// TODO: XXX TMC: Migrate to a more data-driven solution.
	AssetPath fontPath;
	AssetPtr spFont;

	HELIUM_VERIFY( fontPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Fonts" HELIUM_OBJECT_PATH_CHAR_STRING "DebugSmall" ) );
	HELIUM_VERIFY( pAssetLoader->LoadObject( fontPath, spFont ) );
	m_debugFonts[DEBUG_FONT_SIZE_SMALL] = Reflect::SafeCast< Font >( spFont.Get() );
	spFont.Release();

	HELIUM_VERIFY( fontPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Fonts" HELIUM_OBJECT_PATH_CHAR_STRING "DebugMedium" ) );
	HELIUM_VERIFY( pAssetLoader->LoadObject( fontPath, spFont ) );
	m_debugFonts[DEBUG_FONT_SIZE_MEDIUM] = Reflect::SafeCast< Font >( spFont.Get() );
	spFont.Release();

	HELIUM_VERIFY( fontPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Fonts" HELIUM_OBJECT_PATH_CHAR_STRING "DebugLarge" ) );
	HELIUM_VERIFY( pAssetLoader->LoadObject( fontPath, spFont ) );
	m_debugFonts[DEBUG_FONT_SIZE_LARGE] = Reflect::SafeCast< Font >( spFont.Get() );
	spFont.Release();

#endif

	return true;
}