/* * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. * Copyright (C) 2022 Stephen Pridham (id Tech 4x integration) * * 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 "precompiled.h" #pragma hdrstop #include "RenderPass.h" #include "Passes/CommonPasses.h" #include static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 }; #define MAX_VERTS 8000 #define MAX_INDEXES 120000 idDrawVert* BasicTriangle::AllocVerts( int vertCount, triIndex_t* tempIndexes, int indexCount ) { if( numIndexes + indexCount > MAX_INDEXES ) { static int warningFrame = 0; if( warningFrame != tr.frameCount ) { warningFrame = tr.frameCount; idLib::Warning( "idGuiModel::AllocTris: MAX_INDEXES exceeded" ); } return NULL; } if( numVerts + vertCount > MAX_VERTS ) { static int warningFrame = 0; if( warningFrame != tr.frameCount ) { warningFrame = tr.frameCount; idLib::Warning( "idGuiModel::AllocTris: MAX_VERTS exceeded" ); } return NULL; } int startVert = numVerts; int startIndex = numIndexes; numVerts += vertCount; numIndexes += indexCount; if( ( startIndex & 1 ) || ( indexCount & 1 ) ) { // slow for write combined memory! // this should be very rare, since quads are always an even index count for( int i = 0; i < indexCount; i++ ) { indexPointer[startIndex + i] = startVert + tempIndexes[i]; } } else { for( int i = 0; i < indexCount; i += 2 ) { WriteIndexPair( indexPointer + startIndex + i, startVert + tempIndexes[i], startVert + tempIndexes[i + 1] ); } } return vertexPointer + startVert; } bool BasicTriangle::Init() { int v = renderProgManager.FindShader( "vertbuffershaders.hlsl", SHADER_STAGE_VERTEX ); int f = renderProgManager.FindShader( "vertbuffershaders.hlsl", SHADER_STAGE_FRAGMENT ); vertexShader = renderProgManager.GetShader( v ); pixelShader = renderProgManager.GetShader( f ); if( !vertexShader || !pixelShader ) { return false; } commandList = GetDevice()->createCommandList(); nvrhi::VertexAttributeDesc attributes[] = { nvrhi::VertexAttributeDesc() .setName( "POSITION" ) .setFormat( nvrhi::Format::RGB32_FLOAT ) .setOffset( offsetof( idDrawVert, xyz ) ) .setElementStride( sizeof( idDrawVert ) ), //nvrhi::VertexAttributeDesc() // .setName( "NORMAL" ) // .setFormat( nvrhi::Format::RGBA8_UINT ) // .setOffset( offsetof( idDrawVert, normal ) ) // .setElementStride( sizeof( idDrawVert ) ), //nvrhi::VertexAttributeDesc() // .setName( "COLOR" ) // .setFormat( nvrhi::Format::RGBA8_UINT ) // .setOffset( offsetof( idDrawVert, color ) ) // .setElementStride( sizeof( idDrawVert ) ), //nvrhi::VertexAttributeDesc() // .setName( "COLOR2" ) // .setFormat( nvrhi::Format::RGBA8_UINT ) // .setOffset( offsetof( idDrawVert, color2 ) ) // .setElementStride( sizeof( idDrawVert ) ), nvrhi::VertexAttributeDesc() .setName( "UV" ) .setFormat( nvrhi::Format::RG16_FLOAT ) .setOffset( offsetof( idDrawVert, st ) ) .setElementStride( sizeof( idDrawVert ) ), //nvrhi::VertexAttributeDesc() // .setName( "TANGENT" ) // .setFormat( nvrhi::Format::RGBA8_UINT ) // .setOffset( offsetof( idDrawVert, tangent ) ) // .setElementStride( sizeof( idDrawVert ) ), }; inputLayout = GetDevice()->createInputLayout( attributes, uint32_t( std::size( attributes ) ), vertexShader ); material = declManager->FindMaterial( "guis/rml/shell/textures/invader" ); commandList->open(); for( int i = 0; i < material->GetNumStages(); i++ ) { material->GetStage( i )->texture.image->ActuallyLoadImage( true, commandList ); } commandList->close(); GetDevice()->executeCommandList( commandList ); GetDevice()->runGarbageCollection(); nvrhi::ITexture* texture = ( nvrhi::ITexture* )material->GetStage( 0 )->texture.image->GetTextureID(); CommonRenderPasses commonPasses; commonPasses.Init( GetDevice() ); idUniformBuffer& ubo = renderProgManager.BindingParamUbo(); nvrhi::BindingSetDesc bindingSetDesc; bindingSetDesc.bindings = { nvrhi::BindingSetItem::ConstantBuffer( 0, ubo.GetAPIObject(), nvrhi::BufferRange( ubo.GetOffset(), ubo.GetSize() ) ), nvrhi::BindingSetItem::Texture_SRV( 0, texture ), nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ) }; if( !nvrhi::utils::CreateBindingSetAndLayout( GetDevice(), nvrhi::ShaderType::All, 0, bindingSetDesc, bindingLayout, bindingSet ) ) { common->Error( "Couldn't create the binding set or layout" ); return false; } return true; } void BasicTriangle::BackBufferResizing() { pipeline = nullptr; } void BasicTriangle::Animate( float fElapsedTimeSeconds ) { } void BasicTriangle::RenderFrontend() { vertexBlock = vertexCache.AllocVertex( NULL, MAX_VERTS, sizeof( idDrawVert ), commandList ); indexBlock = vertexCache.AllocIndex( NULL, MAX_INDEXES, sizeof( triIndex_t ), commandList ); vertexPointer = ( idDrawVert* )vertexCache.MappedVertexBuffer( vertexBlock ); indexPointer = ( triIndex_t* )vertexCache.MappedIndexBuffer( indexBlock ); numVerts = 0; numIndexes = 0; idDrawVert* verts = AllocVerts( 4, quadPicIndexes, 6 ); uint32_t currentColorNativeBytesOrder = LittleLong( PackColor( idVec4( 255, 255, 255, 255 ) ) ); float x = 0.f; float y = 0.f; float w = renderSystem->GetWidth(); float h = renderSystem->GetHeight(); float s1 = 0.0f, t1 = 0.0f, s2 = 1.0f, t2 = 1.0f; idVec4 topLeft( x, y, s1, t1 ); idVec4 topRight( x + w, y, s2, t1 ); idVec4 bottomRight( x + w, y + h, s2, t2 ); idVec4 bottomLeft( x, y + h, s1, t2 ); float z = 0.0f; ALIGNTYPE16 idDrawVert localVerts[4]; localVerts[0].Clear(); localVerts[0].xyz[0] = x; localVerts[0].xyz[1] = y; localVerts[0].xyz[2] = 0.f; localVerts[0].SetTexCoord( s1, t1 ); localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[0].ClearColor2(); localVerts[1].Clear(); localVerts[1].xyz[0] = x + w; localVerts[1].xyz[1] = y; localVerts[1].xyz[2] = 0.f; localVerts[1].SetTexCoord( s2, t1 ); localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[1].ClearColor2(); localVerts[2].Clear(); localVerts[2].xyz[0] = x + w; localVerts[2].xyz[1] = y + h; localVerts[2].xyz[2] = 0.f; localVerts[2].SetTexCoord( s2, t2 ); localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[2].ClearColor2(); localVerts[3].Clear(); localVerts[3].xyz[0] = x; localVerts[3].xyz[1] = y + h; localVerts[3].xyz[2] = 0.f; localVerts[3].SetTexCoord( s1, t2 ); localVerts[3].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[3].ClearColor2(); WriteDrawVerts16( verts, localVerts, 4 ); for( int i = 0; i < 6; i += 2 ) { WriteIndexPair( indexPointer + i, quadPicIndexes[i], quadPicIndexes[i + 1] ); } } void BasicTriangle::Render( nvrhi::IFramebuffer* framebuffer ) { if( !pipeline ) { nvrhi::GraphicsPipelineDesc psoDesc; psoDesc.VS = vertexShader; psoDesc.PS = pixelShader; psoDesc.inputLayout = inputLayout; psoDesc.bindingLayouts = { bindingLayout }; psoDesc.primType = nvrhi::PrimitiveType::TriangleList; psoDesc.renderState.depthStencilState.depthTestEnable = false; //psoDesc.renderState.rasterState.frontCounterClockwise = true; pipeline = GetDevice()->createGraphicsPipeline( psoDesc, framebuffer ); } commandList->open(); commandList->beginMarker( "Basic" ); RenderFrontend(); nvrhi::utils::ClearColorAttachment( commandList, framebuffer, 0, nvrhi::Color( 0.f ) ); float w = framebuffer->getFramebufferInfo().width; float h = framebuffer->getFramebufferInfo().height; idRenderMatrix projectionMatrix; { // orthographic matrix float xScale = 1.0f / w; float yScale = -1.0f / h; // flip y float zScale = 1.0f; float projMat[16]; projMat[0 * 4 + 0] = 2.f * xScale; projMat[0 * 4 + 1] = 0.0f; projMat[0 * 4 + 2] = 0.0f; projMat[0 * 4 + 3] = 0.0f; projMat[1 * 4 + 0] = 0.0f; projMat[1 * 4 + 1] = 2.f * yScale; projMat[1 * 4 + 2] = 0.0f; projMat[1 * 4 + 3] = 0.0f; projMat[2 * 4 + 0] = 0.0f; projMat[2 * 4 + 1] = 0.0f; projMat[2 * 4 + 2] = zScale; projMat[2 * 4 + 3] = 0.0f; projMat[3 * 4 + 0] = -( w * xScale ); projMat[3 * 4 + 1] = -( h * yScale ); projMat[3 * 4 + 2] = 0.0f; projMat[3 * 4 + 3] = 1.0f; float projMatT[16]; R_MatrixTranspose( projMat, projMatT ); renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_X, &projMat[0] ); renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_Y, &projMat[4] ); renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_Z, &projMat[8] ); renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_W, &projMat[12] ); } renderProgManager.CommitConstantBuffer( commandList, true ); idVertexBuffer* vertexBuffer; uint vertOffset = 0; { if( vertexCache.CacheIsStatic( vertexBlock ) ) { vertexBuffer = &vertexCache.staticData.vertexBuffer; } else { const uint64 frameNum = ( int )( vertexBlock >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; if( frameNum != ( ( vertexCache.currentFrame ) & VERTCACHE_FRAME_MASK ) ) { idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" ); return; } vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer; } vertOffset = ( uint )( vertexBlock >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; } vertCacheHandle_t indexBlockTemp = indexBlock + ( ( int64 )( 0 * sizeof( triIndex_t ) ) << VERTCACHE_OFFSET_SHIFT ); idIndexBuffer* indexBuffer; uint indexOffset = 0; if( vertexCache.CacheIsStatic( indexBlockTemp ) ) { indexBuffer = &vertexCache.staticData.indexBuffer; } else { const uint64 frameNum = ( int )( indexBlockTemp >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; if( frameNum != ( ( vertexCache.currentFrame ) & VERTCACHE_FRAME_MASK ) ) { idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" ); return; } indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer; } indexOffset = ( uint )( indexBlock >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; nvrhi::GraphicsState state; state.bindings = { bindingSet }; state.indexBuffer = { indexBuffer->GetAPIObject(), nvrhi::Format::R16_UINT, indexOffset }; state.vertexBuffers = { { vertexBuffer->GetAPIObject(), 0, vertOffset } }; state.pipeline = pipeline; state.framebuffer = framebuffer; state.viewport.addViewportAndScissorRect( framebuffer->getFramebufferInfo().getViewport() ); commandList->setGraphicsState( state ); nvrhi::DrawArguments args; args.vertexCount = 6; commandList->drawIndexed( args ); commandList->endMarker(); commandList->close(); GetDevice()->executeCommandList( commandList ); }