// 渲染 ///////////////////////////////////////////////////////////////////////////////// void OGLESRenderEngine::DoRender(RenderTechnique const & tech, RenderLayout const & rl) { uint32_t const num_instance = rl.NumInstances(); BOOST_ASSERT(num_instance != 0); OGLESShaderObjectPtr cur_shader = checked_pointer_cast<OGLESShaderObject>(tech.Pass(0)->GetShaderObject()); checked_cast<OGLESRenderLayout const *>(&rl)->Active(cur_shader); size_t const vertexCount = rl.UseIndices() ? rl.NumIndices() : rl.NumVertices(); GLenum mode; uint32_t primCount; OGLESMapping::Mapping(mode, primCount, rl); numPrimitivesJustRendered_ += num_instance * primCount; numVerticesJustRendered_ += num_instance * vertexCount; GLenum index_type = GL_UNSIGNED_SHORT; uint8_t* index_offset = nullptr; if (rl.UseIndices()) { if (EF_R16UI == rl.IndexStreamFormat()) { index_type = GL_UNSIGNED_SHORT; index_offset += rl.StartIndexLocation() * 2; } else { index_type = GL_UNSIGNED_INT; index_offset += rl.StartIndexLocation() * 4; } } uint32_t const num_passes = tech.NumPasses(); size_t const inst_format_size = rl.InstanceStreamFormat().size(); if (glloader_GLES_VERSION_3_0() && rl.InstanceStream()) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(rl.InstanceStream())); uint32_t const instance_size = rl.InstanceSize(); BOOST_ASSERT(num_instance * instance_size <= stream.Size()); uint8_t* elem_offset = nullptr; for (size_t i = 0; i < inst_format_size; ++ i) { vertex_element const & vs_elem = rl.InstanceStreamFormat()[i]; GLint attr = cur_shader->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLESMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; GLvoid* offset = static_cast<GLvoid*>(elem_offset + rl.StartInstanceLocation() * instance_size); stream.Active(false); glVertexAttribPointer(attr, num_components, type, normalized, instance_size, offset); glEnableVertexAttribArray(attr); glVertexAttribDivisor(attr, 1); } elem_offset += vs_elem.element_size(); } if (so_rl_) { glBeginTransformFeedback(so_primitive_mode_); } if (rl.UseIndices()) { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawElementsInstanced(mode, static_cast<GLsizei>(rl.NumIndices()), index_type, index_offset, num_instance); pass->Unbind(); } } else { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawArraysInstanced(mode, rl.StartVertexLocation(), static_cast<GLsizei>(rl.NumVertices()), num_instance); pass->Unbind(); } } if (so_rl_) { glEndTransformFeedback(); } for (size_t i = 0; i < inst_format_size; ++ i) { vertex_element const & vs_elem = rl.InstanceStreamFormat()[i]; GLint attr = cur_shader->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { glDisableVertexAttribArray(attr); glVertexAttribDivisor(attr, 0); } } } else { for (uint32_t instance = rl.StartInstanceLocation(); instance < rl.StartInstanceLocation() + num_instance; ++ instance) { if (rl.InstanceStream()) { GraphicsBuffer& stream = *rl.InstanceStream(); uint32_t const instance_size = rl.InstanceSize(); BOOST_ASSERT(num_instance * instance_size <= stream.Size()); GraphicsBuffer::Mapper mapper(stream, BA_Read_Only); uint8_t const * buffer = mapper.Pointer<uint8_t>(); uint32_t elem_offset = 0; for (size_t i = 0; i < inst_format_size; ++ i) { BOOST_ASSERT(elem_offset < instance_size); vertex_element const & vs_elem = rl.InstanceStreamFormat()[i]; GLint attr = cur_shader->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { void const * addr = &buffer[instance * instance_size + elem_offset]; GLfloat const * float_addr = static_cast<GLfloat const *>(addr); GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLESMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; switch (num_components) { case 1: BOOST_ASSERT(IsFloatFormat(vs_elem.format)); glVertexAttrib1fv(attr, float_addr); break; case 2: BOOST_ASSERT(IsFloatFormat(vs_elem.format)); glVertexAttrib2fv(attr, float_addr); break; case 3: BOOST_ASSERT(IsFloatFormat(vs_elem.format)); glVertexAttrib3fv(attr, float_addr); break; case 4: if (IsFloatFormat(vs_elem.format)) { glVertexAttrib4fv(attr, float_addr); } else { GLubyte const * byte_addr = static_cast<GLubyte const *>(addr); if (normalized) { glVertexAttrib4f(attr, byte_addr[0] / 255.0f, byte_addr[1] / 255.0f, byte_addr[2] / 255.0f, byte_addr[3] / 255.0f); } else { glVertexAttrib4f(attr, byte_addr[0], byte_addr[1], byte_addr[2], byte_addr[3]); } } break; default: BOOST_ASSERT(false); break; } } elem_offset += vs_elem.element_size(); } } if (so_rl_) { glBeginTransformFeedback(so_primitive_mode_); } if (rl.UseIndices()) { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawElements(mode, static_cast<GLsizei>(rl.NumIndices()), index_type, index_offset); pass->Unbind(); } } else { for (uint32_t i = 0; i < num_passes; ++ i) { RenderPassPtr const & pass = tech.Pass(i); pass->Bind(); if (so_rl_) { OGLESShaderObjectPtr shader = checked_pointer_cast<OGLESShaderObject>(pass->GetShaderObject()); glTransformFeedbackVaryings(shader->GLSLProgram(), static_cast<GLsizei>(so_vars_ptrs_.size()), &so_vars_ptrs_[0], GL_SEPARATE_ATTRIBS); for (uint32_t j = 0; j < so_buffs_.size(); ++ j) { glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, j, so_buffs_[j]); } } glDrawArrays(mode, rl.StartVertexLocation(), static_cast<GLsizei>(rl.NumVertices())); pass->Unbind(); } } if (so_rl_) { glEndTransformFeedback(); } } } checked_cast<OGLESRenderLayout const *>(&rl)->Deactive(cur_shader); }
void OGLRenderLayout::BindVertexStreams(ShaderObjectPtr const & so, GLuint vao) const { OGLShaderObjectPtr const & ogl_so = checked_pointer_cast<OGLShaderObject>(so); RenderEngine& re = Context::Instance().RenderFactoryInstance().RenderEngineInstance(); uint32_t max_vertex_streams = re.DeviceCaps().max_vertex_streams; std::vector<char> used_streams(max_vertex_streams, 0); for (uint32_t i = 0; i < this->NumVertexStreams(); ++ i) { OGLGraphicsBuffer& stream(*checked_pointer_cast<OGLGraphicsBuffer>(this->GetVertexStream(i))); uint32_t const size = this->VertexSize(i); auto const & vertex_stream_fmt = this->VertexStreamFormat(i); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayVertexBuffer(vao, i, stream.GLvbo(), this->StartVertexLocation() * size, size); } uint32_t elem_offset = 0; for (auto const & vs_elem : vertex_stream_fmt) { GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLintptr offset = elem_offset + this->StartVertexLocation() * size; GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; BOOST_ASSERT(GL_ARRAY_BUFFER == stream.GLType()); stream.Active(true); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayAttribFormat(vao, attr, num_components, type, normalized, elem_offset); glVertexArrayAttribBinding(vao, attr, i); glEnableVertexArrayAttrib(vao, attr); } else if (glloader_GL_EXT_direct_state_access()) { glVertexArrayVertexAttribOffsetEXT(vao, stream.GLvbo(), attr, num_components, type, normalized, size, offset); glEnableVertexArrayAttribEXT(vao, attr); } else { glVertexAttribPointer(attr, num_components, type, normalized, size, reinterpret_cast<GLvoid*>(offset)); glEnableVertexAttribArray(attr); } used_streams[attr] = 1; } elem_offset += vs_elem.element_size(); } } if (this->InstanceStream()) { OGLGraphicsBuffer& stream(*checked_pointer_cast<OGLGraphicsBuffer>(this->InstanceStream())); uint32_t const instance_size = this->InstanceSize(); BOOST_ASSERT(this->NumInstances() * instance_size <= stream.Size()); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayVertexBuffer(vao, this->NumVertexStreams(), stream.GLvbo(), this->StartInstanceLocation() * instance_size, instance_size); glVertexArrayBindingDivisor(vao, this->NumVertexStreams(), 1); } size_t const inst_format_size = this->InstanceStreamFormat().size(); uint32_t elem_offset = 0; for (size_t i = 0; i < inst_format_size; ++ i) { VertexElement const & vs_elem = this->InstanceStreamFormat()[i]; GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; GLintptr offset = elem_offset + this->StartInstanceLocation() * instance_size; BOOST_ASSERT(GL_ARRAY_BUFFER == stream.GLType()); stream.Active(true); if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glVertexArrayAttribFormat(vao, attr, num_components, type, normalized, elem_offset); glVertexArrayAttribBinding(vao, attr, this->NumVertexStreams()); glEnableVertexArrayAttrib(vao, attr); } else if (glloader_GL_EXT_direct_state_access()) { glVertexArrayVertexAttribOffsetEXT(vao, stream.GLvbo(), attr, num_components, type, normalized, instance_size, offset); glEnableVertexArrayAttribEXT(vao, attr); glVertexAttribDivisor(attr, 1); } else { glVertexAttribPointer(attr, num_components, type, normalized, instance_size, reinterpret_cast<GLvoid*>(offset)); glEnableVertexAttribArray(attr); glVertexAttribDivisor(attr, 1); } used_streams[attr] = 1; } elem_offset += vs_elem.element_size(); } } for (GLuint i = 0; i < max_vertex_streams; ++ i) { if (!used_streams[i]) { if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glDisableVertexArrayAttrib(vao, i); } else if (glloader_GL_EXT_direct_state_access()) { glDisableVertexArrayAttribEXT(vao, i); } else { glDisableVertexAttribArray(i); } } } }
void OGLESRenderLayout::BindVertexStreams(ShaderObjectPtr const & so) const { OGLESShaderObjectPtr const & ogl_so = checked_pointer_cast<OGLESShaderObject>(so); RenderEngine& re = Context::Instance().RenderFactoryInstance().RenderEngineInstance(); uint32_t max_vertex_streams = re.DeviceCaps().max_vertex_streams; std::vector<char> used_streams(max_vertex_streams, 0); for (uint32_t i = 0; i < this->NumVertexStreams(); ++ i) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->GetVertexStream(i))); uint32_t const size = this->VertexSize(i); vertex_elements_type const & vertex_stream_fmt = this->VertexStreamFormat(i); uint8_t* elem_offset = nullptr; for (auto const & vs_elem : vertex_stream_fmt) { GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLvoid* offset = static_cast<GLvoid*>(elem_offset + this->StartVertexLocation() * size); GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLESMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; BOOST_ASSERT(GL_ARRAY_BUFFER == stream.GLType()); stream.Active(use_vao_); glVertexAttribPointer(attr, num_components, type, normalized, size, offset); glEnableVertexAttribArray(attr); used_streams[attr] = 1; } elem_offset += vs_elem.element_size(); } } if (this->InstanceStream() && (glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_instanced_arrays())) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->InstanceStream())); uint32_t const instance_size = this->InstanceSize(); BOOST_ASSERT(this->NumInstances() * instance_size <= stream.Size()); size_t const inst_format_size = this->InstanceStreamFormat().size(); uint8_t* elem_offset = nullptr; for (size_t i = 0; i < inst_format_size; ++ i) { vertex_element const & vs_elem = this->InstanceStreamFormat()[i]; GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { GLint const num_components = static_cast<GLint>(NumComponents(vs_elem.format)); GLenum type; GLboolean normalized; OGLESMapping::MappingVertexFormat(type, normalized, vs_elem.format); normalized = (((VEU_Diffuse == vs_elem.usage) || (VEU_Specular == vs_elem.usage)) && !IsFloatFormat(vs_elem.format)) ? GL_TRUE : normalized; GLvoid* offset = static_cast<GLvoid*>(elem_offset + this->StartInstanceLocation() * instance_size); BOOST_ASSERT(GL_ARRAY_BUFFER == stream.GLType()); stream.Active(use_vao_); glVertexAttribPointer(attr, num_components, type, normalized, instance_size, offset); glEnableVertexAttribArray(attr); if (glloader_GLES_VERSION_3_0()) { glVertexAttribDivisor(attr, 1); } else { glVertexAttribDivisorEXT(attr, 1); } used_streams[attr] = 1; } elem_offset += vs_elem.element_size(); } } for (GLuint i = 0; i < max_vertex_streams; ++ i) { if (!used_streams[i]) { glDisableVertexAttribArray(i); } } OGLESRenderEngine& ogl_re = *checked_cast<OGLESRenderEngine*>(&re); if (!(ogl_re.HackForMali() || ogl_re.HackForAdreno()) && this->UseIndices()) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->GetIndexStream())); BOOST_ASSERT(GL_ELEMENT_ARRAY_BUFFER == stream.GLType()); stream.Active(use_vao_); } }