gl::GLenum DrawExecution::elementType() const { Assert(m_drawImpl.indexBuffer.get(), "No index buffer set"); Assert(m_drawImpl.indexBuffer->layout.fields().size() == 1u, "Invalid index buffer layout"); return TypeToGLType(m_drawImpl.indexBuffer->layout.fields()[0].type()); }
const GLObjectWrappers::GLVertexArrayObj& VAOCache::GetVAO( IPipelineState *pPSO, IBuffer *pIndexBuffer, VertexStreamInfo VertexStreams[], Uint32 NumVertexStreams, GLContextState &GLContextState ) { // Lock the cache ThreadingTools::LockHelper CacheLock(m_CacheLockFlag); IBuffer* VertexBuffers[MaxBufferSlots]; for (Uint32 s = 0; s < NumVertexStreams; ++s) VertexBuffers[s] = nullptr; // Get layout auto *pPSOGL = ValidatedCast<PipelineStateGLImpl>(pPSO); const auto &InputLayout = pPSOGL->GetDesc().GraphicsPipeline.InputLayout; const LayoutElement *LayoutElems = InputLayout.LayoutElements; Uint32 NumElems = InputLayout.NumElements; const Uint32 *TightStrides = pPSOGL->GetTightStrides(); // Construct the key VAOCacheKey Key(pPSO, pIndexBuffer); { auto LayoutIt = LayoutElems; for (size_t Elem = 0; Elem < NumElems; ++Elem, ++LayoutIt) { auto BuffSlot = LayoutIt->BufferSlot; if (BuffSlot >= NumVertexStreams) { UNEXPECTED("Input layout requires more buffers than bound to the pipeline"); continue; } if (BuffSlot >= MaxBufferSlots) { VERIFY(BuffSlot >= MaxBufferSlots, "Incorrect input slot"); continue; } auto MaxUsedSlot = std::max(Key.NumUsedSlots, BuffSlot + 1); for (Uint32 s = Key.NumUsedSlots; s < MaxUsedSlot; ++s) Key.Streams[s] = VAOCacheKey::StreamAttribs{}; Key.NumUsedSlots = MaxUsedSlot; auto &CurrStream = VertexStreams[BuffSlot]; auto Stride = CurrStream.Stride ? CurrStream.Stride : TightStrides[BuffSlot]; auto &pCurrBuf = VertexBuffers[BuffSlot]; auto &CurrStreamKey = Key.Streams[BuffSlot]; if (pCurrBuf == nullptr) { pCurrBuf = CurrStream.pBuffer; VERIFY(pCurrBuf != nullptr, "No buffer bound to slot ", BuffSlot); ValidatedCast<BufferGLImpl>(pCurrBuf)->BufferMemoryBarrier( GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT,// Vertex data sourced from buffer objects after the barrier // will reflect data written by shaders prior to the barrier. // The set of buffer objects affected by this bit is derived // from the GL_VERTEX_ARRAY_BUFFER_BINDING bindings GLContextState); CurrStreamKey.pBuffer = pCurrBuf; CurrStreamKey.Stride = Stride; CurrStreamKey.Offset = CurrStream.Offset; } else { VERIFY(pCurrBuf == CurrStream.pBuffer, "Buffer no longer exists"); VERIFY(CurrStreamKey.pBuffer == pCurrBuf, "Unexpected buffer"); VERIFY(CurrStreamKey.Stride == Stride, "Unexpected buffer stride"); VERIFY(CurrStreamKey.Offset == CurrStream.Offset, "Unexpected buffer offset"); } } } if( pIndexBuffer ) { ValidatedCast<BufferGLImpl>(pIndexBuffer)->BufferMemoryBarrier( GL_ELEMENT_ARRAY_BARRIER_BIT,// Vertex array indices sourced from buffer objects after the barrier // will reflect data written by shaders prior to the barrier. // The buffer objects affected by this bit are derived from the // ELEMENT_ARRAY_BUFFER binding. GLContextState); } // Try to find VAO in the map auto It = m_Cache.find(Key); if( It != m_Cache.end() ) { return It->second; } else { // Create new VAO GLObjectWrappers::GLVertexArrayObj NewVAO(true); // Initialize VAO GLContextState.BindVAO( NewVAO ); auto LayoutIt = LayoutElems; for( size_t Elem = 0; Elem < NumElems; ++Elem, ++LayoutIt ) { auto BuffSlot = LayoutIt->BufferSlot; if( BuffSlot >= NumVertexStreams || BuffSlot >= MaxBufferSlots ) { UNEXPECTED( "Incorrect input buffer slot" ); continue; } // Get buffer through the strong reference. Note that we are not // using pointers stored in the key for safety auto &CurrStream = VertexStreams[BuffSlot]; auto Stride = CurrStream.Stride ? CurrStream.Stride : TightStrides[BuffSlot]; auto *pBuff = VertexBuffers[BuffSlot]; VERIFY( pBuff != nullptr, "Vertex buffer is null" ); const BufferGLImpl *pBufferOGL = static_cast<const BufferGLImpl*>( pBuff ); glBindBuffer(GL_ARRAY_BUFFER, pBufferOGL->m_GlBuffer); GLvoid* DataStartOffset = reinterpret_cast<GLvoid*>( static_cast<size_t>( CurrStream.Offset + LayoutIt->RelativeOffset ) ); auto GlType = TypeToGLType(LayoutIt->ValueType); if( !LayoutIt->IsNormalized && (LayoutIt->ValueType == VT_INT8 || LayoutIt->ValueType == VT_INT16 || LayoutIt->ValueType == VT_INT32 || LayoutIt->ValueType == VT_UINT8 || LayoutIt->ValueType == VT_UINT16|| LayoutIt->ValueType == VT_UINT32 ) ) glVertexAttribIPointer(LayoutIt->InputIndex, LayoutIt->NumComponents, GlType, Stride, DataStartOffset ); else glVertexAttribPointer(LayoutIt->InputIndex, LayoutIt->NumComponents, GlType, LayoutIt->IsNormalized, Stride, DataStartOffset ); if( LayoutIt->Frequency == LayoutElement::FREQUENCY_PER_INSTANCE ) { // If divisor is zero, then the attribute acts like normal, being indexed by the array or index // buffer. If divisor is non-zero, then the current instance is divided by this divisor, and // the result of that is used to access the attribute array. glVertexAttribDivisor(LayoutIt->InputIndex, LayoutIt->InstanceDataStepRate); } glEnableVertexAttribArray(LayoutIt->InputIndex); } if( pIndexBuffer ) { const BufferGLImpl *pIndBufferOGL = static_cast<const BufferGLImpl*>( pIndexBuffer ); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pIndBufferOGL->m_GlBuffer); } auto NewElems = m_Cache.emplace( std::make_pair(Key, std::move(NewVAO)) ); // New element must be actually inserted VERIFY( NewElems.second, "New element was not inserted into the cache" ); m_PSOToKey.insert( std::make_pair(Key.pPSO, Key) ); for(Uint32 Slot = 0; Slot < Key.NumUsedSlots; ++Slot) { auto *pCurrBuff = Key.Streams[Slot].pBuffer; if( pCurrBuff ) m_BuffToKey.insert( std::make_pair(pCurrBuff, Key) ); } return NewElems.first->second; } }
void DrawExecution::perform() { m_glStateManager.enableTextureCubeMapSeamless(true); // Apply State applyDepthState(); applyBlendState(); applyCullState(); applyRasterizerState(); applyStencilState(); applyViewport(); gl::glUseProgram(m_drawImpl.program->glProgramName); // Setup texture units for (auto b = 0u; b < m_drawImpl.samplers.size(); b++) { auto & sampler = m_drawImpl.samplers[b]; auto * texture = sampler.texture; Assert(texture, ""); if (texture->glName == 0) { texture->allocate(); } gl::glActiveTexture(gl::GL_TEXTURE0 + b); gl::glBindTexture(texture->type, texture->glName); gl::glTexParameteri(texture->type, gl::GL_TEXTURE_BASE_LEVEL, texture->baseLevel); gl::glTexParameteri(texture->type, gl::GL_TEXTURE_MAX_LEVEL, texture->maxLevel); gl::glBindSampler(b, sampler.glSampler.name()); gl::glSamplerParameteri(sampler.glSampler.name(), gl::GL_TEXTURE_MIN_FILTER, (gl::GLint)texture->minFilter); gl::glSamplerParameteri(sampler.glSampler.name(), gl::GL_TEXTURE_MAG_FILTER, (gl::GLint)texture->maxFilter); gl::glUniform1i(sampler.location, b); } // Setup RenderTarget / Framebuffer Assert(m_drawImpl.framebuffer.m_impl.get(), ""); m_drawImpl.framebuffer.m_impl->bind(m_glStateManager); // Set uniforms { /* TODO Port to GLStateManager */ for (auto & uniform : m_drawImpl.uniforms) { Assert(uniform.isAssigned, "Uniform " + m_drawImpl.program->interface.uniformByLocation(uniform.location)->name() + " not set"); Assert(uniform.count > 0, ""); auto count = uniform.count; auto * data = uniform.blob.ptr(); auto location = uniform.location; switch (TypeToGLType(uniform.type)) { case gl::GL_INT: gl::glUniform1iv(location, count, ((const gl::GLint*)data)); break; case gl::GL_UNSIGNED_INT: gl::glUniform1uiv(location, count, ((const gl::GLuint*)data)); break; case gl::GL_INT_VEC2: { auto idata = (const gl::GLint*)data; gl::glUniform2iv(location, count, idata); break; } case gl::GL_FLOAT: gl::glUniform1fv(location, count, ((const gl::GLfloat*)data)); break; case gl::GL_FLOAT_VEC2: { auto fdata = (const gl::GLfloat*)data; gl::glUniform2fv(location, count, fdata); break; } case gl::GL_FLOAT_VEC3: { auto fdata = (const gl::GLfloat*)data; gl::glUniform3fv(location, count, fdata); break; } case gl::GL_FLOAT_VEC4: { auto fdata = (const gl::GLfloat*)data; gl::glUniform4fv(location, count, fdata); break; } case gl::GL_FLOAT_MAT4: gl::glUniformMatrix4fv(location, count, gl::GL_FALSE, (const gl::GLfloat*)data); break; default: Fail(std::string("Not implemented for type ") + uniform.type.name()); } } } // Set uniform buffers { for (auto b = 0; b < m_drawImpl.uniformBuffers.size(); b++) { auto & binding = m_drawImpl.uniformBuffers[b]; Assert(binding.engaged(), "UniformBuffer " + m_drawImpl.program->interface.uniformBlocks()[b].name() + " not bound"); auto & buffer = *binding.get().buffer; auto size = buffer.count * buffer.layout.stride(); Assert(size > binding.get().begin, "begin beyond buffer bounds"); gl::glUniformBlockBinding(m_drawImpl.program->glProgramName, b, b); gl::glBindBufferRange(gl::GL_UNIFORM_BUFFER, b, buffer.glName, binding.get().begin, buffer.layout.stride()); } } // Dispatch draw if (m_drawImpl.indexBuffer) { if (!m_drawImpl.instanceBuffers.empty()) { drawElementsInstanced(); } else { drawElements(); } } else { if (!m_drawImpl.instanceBuffers.empty()) { drawArraysInstanced(); } else { drawArrays(); } } }