OGLESTexture::OGLESTexture(TextureType type, uint32_t array_size, uint32_t sample_count, uint32_t sample_quality, uint32_t access_hint) : Texture(type, sample_count, sample_quality, access_hint), hw_res_ready_(false) { array_size_ = array_size; if ((array_size > 1) && !glloader_GLES_VERSION_3_0()) { THR(errc::function_not_supported); } switch (type_) { case TT_1D: case TT_2D: if (array_size > 1) { target_type_ = GL_TEXTURE_2D_ARRAY; } else { target_type_ = GL_TEXTURE_2D; } break; case TT_3D: if (!glloader_GLES_VERSION_3_0() && !glloader_GLES_OES_texture_3D()) { THR(errc::function_not_supported); } if (glloader_GLES_VERSION_3_0()) { target_type_ = GL_TEXTURE_3D; } else { target_type_ = GL_TEXTURE_3D_OES; } break; case TT_Cube: target_type_ = GL_TEXTURE_CUBE_MAP; break; default: BOOST_ASSERT(false); target_type_ = GL_TEXTURE_2D; break; } glGenTextures(1, &texture_); glBindTexture(target_type_, texture_); glTexParameteri(target_type_, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(target_type_, GL_TEXTURE_MIN_FILTER, GL_NEAREST); }
void OGLESFrameBuffer::OnBind() { OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); re.BindFramebuffer(fbo_); BOOST_ASSERT(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)); if (glloader_GLES_VERSION_3_0()) { if (fbo_ != 0) { std::vector<GLenum> targets(clr_views_.size()); for (size_t i = 0; i < clr_views_.size(); ++ i) { targets[i] = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i); } glDrawBuffers(static_cast<GLsizei>(targets.size()), &targets[0]); } else { GLenum targets[] = { GL_BACK }; glDrawBuffers(1, &targets[0]); } } }
OGLESRenderLayout::OGLESRenderLayout() { if (glloader_GLES_VERSION_3_0()) { use_vao_ = true; } else { use_vao_ = false; } }
QueryPtr OGLESRenderFactory::MakeConditionalRender() { if (glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_occlusion_query_boolean()) { return MakeSharedPtr<OGLESConditionalRender>(); } else { return QueryPtr(); } }
OGLESTexture2D::OGLESTexture2D(uint32_t width, uint32_t height, uint32_t numMipMaps, uint32_t array_size, ElementFormat format, uint32_t sample_count, uint32_t sample_quality, uint32_t access_hint) : OGLESTexture(TT_2D, array_size, sample_count, sample_quality, access_hint) { if (IsSRGB(format)) { format = this->SRGBToRGB(format); } format_ = format; if (0 == numMipMaps) { num_mip_maps_ = 1; uint32_t w = width; uint32_t h = height; while ((w != 1) || (h != 1)) { ++ num_mip_maps_; w = std::max<uint32_t>(1U, w / 2); h = std::max<uint32_t>(1U, h / 2); } } else { num_mip_maps_ = numMipMaps; } width_ = width; height_ = height; tex_data_.resize(array_size_ * num_mip_maps_); glBindTexture(target_type_, texture_); if (glloader_GLES_VERSION_3_0()) { glTexParameteri(target_type_, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL, num_mip_maps_ - 1); } else if (glloader_GLES_APPLE_texture_max_level()) { glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL_APPLE, num_mip_maps_ - 1); } else { OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); if (re.HackForTegra()) { glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL, num_mip_maps_ - 1); } } }
OGLESTexture::OGLESTexture(TextureType type, uint32_t array_size, uint32_t sample_count, uint32_t sample_quality, uint32_t access_hint) : Texture(type, sample_count, sample_quality, access_hint) { if (array_size > 1) { THR(errc::function_not_supported); } switch (type_) { case TT_1D: case TT_2D: target_type_ = GL_TEXTURE_2D; break; case TT_3D: if (!glloader_GLES_VERSION_3_0() && !glloader_GLES_OES_texture_3D()) { THR(errc::function_not_supported); } if (glloader_GLES_VERSION_3_0()) { target_type_ = GL_TEXTURE_3D; } else { target_type_ = GL_TEXTURE_3D_OES; } break; case TT_Cube: target_type_ = GL_TEXTURE_CUBE_MAP; break; default: BOOST_ASSERT(false); target_type_ = GL_TEXTURE_2D; break; } }
void OGLESRenderLayout::UnbindVertexStreams(ShaderObjectPtr const & so) const { OGLESShaderObjectPtr const & ogl_so = checked_pointer_cast<OGLESShaderObject>(so); for (uint32_t i = 0; i < this->NumVertexStreams(); ++ i) { vertex_elements_type const & vertex_stream_fmt = this->VertexStreamFormat(i); for (auto const & vs_elem : vertex_stream_fmt) { GLint attr = ogl_so->GetAttribLocation(vs_elem.usage, vs_elem.usage_index); if (attr != -1) { glDisableVertexAttribArray(attr); } } } if (this->InstanceStream() && (glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_instanced_arrays())) { size_t const inst_format_size = this->InstanceStreamFormat().size(); 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) { glDisableVertexAttribArray(attr); if (glloader_GLES_VERSION_3_0()) { glVertexAttribDivisor(attr, 0); } else { glVertexAttribDivisorEXT(attr, 0); } } } } }
void OGLESTexture3DRenderView::CopyToSlice(uint32_t att) { BOOST_ASSERT(att != FrameBuffer::ATT_DepthStencil); UNREF_PARAM(att); if (glloader_GLES_VERSION_3_0()) { glBindTexture(GL_TEXTURE_3D, tex_); glCopyTexSubImage3D(GL_TEXTURE_3D, level_, 0, 0, slice_, 0, 0, width_, height_); } else { glBindTexture(GL_TEXTURE_3D_OES, tex_); glCopyTexSubImage3DOES(GL_TEXTURE_3D_OES, level_, 0, 0, slice_, 0, 0, width_, height_); } }
void OGLESRenderEngine::InitRenderStates() { RenderFactory& rf = Context::Instance().RenderFactoryInstance(); cur_rs_obj_ = rf.MakeRasterizerStateObject(RasterizerStateDesc()); cur_dss_obj_ = rf.MakeDepthStencilStateObject(DepthStencilStateDesc()); cur_bs_obj_ = rf.MakeBlendStateObject(BlendStateDesc()); checked_pointer_cast<OGLESRasterizerStateObject>(cur_rs_obj_)->ForceDefaultState(); checked_pointer_cast<OGLESDepthStencilStateObject>(cur_dss_obj_)->ForceDefaultState(); checked_pointer_cast<OGLESBlendStateObject>(cur_bs_obj_)->ForceDefaultState(); glEnable(GL_POLYGON_OFFSET_FILL); if (glloader_GLES_VERSION_3_0()) { glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); } active_tex_unit_ = GL_TEXTURE0; glActiveTexture(active_tex_unit_); binded_buffer_.clear(); }
OGLESTextureCubeRenderView::OGLESTextureCubeRenderView(Texture& texture_cube, int array_index, Texture::CubeFaces face, int level) : texture_cube_(*checked_cast<OGLESTextureCube*>(&texture_cube)), face_(face), level_(level) { UNREF_PARAM(array_index); BOOST_ASSERT(Texture::TT_Cube == texture_cube.Type()); BOOST_ASSERT(0 == array_index); uint32_t const channels = NumComponents(texture_cube.Format()); if (((1 == channels) || (2 == channels)) && (!(glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_texture_rg()))) { THR(errc::function_not_supported); } tex_ = texture_cube_.GLTexture(); width_ = texture_cube_.Width(level); height_ = texture_cube_.Height(level); pf_ = texture_cube_.Format(); }
OGLESTexture3DRenderView::OGLESTexture3DRenderView(Texture& texture_3d, int array_index, uint32_t slice, int level) : texture_3d_(*checked_cast<OGLESTexture3D*>(&texture_3d)), slice_(slice), level_(level), copy_to_tex_(0) { UNREF_PARAM(array_index); BOOST_ASSERT(Texture::TT_3D == texture_3d.Type()); BOOST_ASSERT(texture_3d_.Depth(level) > slice); BOOST_ASSERT(0 == array_index); uint32_t const channels = NumComponents(texture_3d.Format()); if (((1 == channels) || (2 == channels)) && (!(glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_texture_rg()))) { THR(errc::function_not_supported); } tex_ = texture_3d_.GLTexture(); width_ = texture_3d_.Width(level); height_ = texture_3d_.Height(level); pf_ = texture_3d_.Format(); }
OGLESTexture2DRenderView::OGLESTexture2DRenderView(Texture& texture_2d, int array_index, int level) : texture_2d_(*checked_cast<OGLESTexture2D*>(&texture_2d)), array_index_(array_index), level_(level) { BOOST_ASSERT(Texture::TT_2D == texture_2d.Type()); if (array_index > 0) { THR(errc::function_not_supported); } uint32_t const channels = NumComponents(texture_2d.Format()); if (((1 == channels) || (2 == channels)) && (!(glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_texture_rg()))) { THR(errc::function_not_supported); } tex_ = texture_2d_.GLTexture(); width_ = texture_2d_.Width(level); height_ = texture_2d_.Height(level); pf_ = texture_2d_.Format(); }
void OGLESFrameBuffer::Discard(uint32_t flags) { if (glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_discard_framebuffer()) { std::vector<GLenum> attachments; if (fbo_ != 0) { if (flags & CBM_Color) { for (size_t i = 0; i < clr_views_.size(); ++ i) { if (clr_views_[i]) { attachments.push_back(static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i)); } } } if (flags & CBM_Depth) { if (rs_view_) { attachments.push_back(GL_DEPTH_ATTACHMENT); } } if (flags & CBM_Stencil) { if (rs_view_) { attachments.push_back(GL_STENCIL_ATTACHMENT); } } } else { if (flags & CBM_Color) { attachments.push_back(GL_COLOR); } if (flags & CBM_Depth) { attachments.push_back(GL_DEPTH); } if (flags & CBM_Stencil) { attachments.push_back(GL_STENCIL); } } OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); GLuint old_fbo = re.BindFramebuffer(); re.BindFramebuffer(fbo_); if (glloader_GLES_VERSION_3_0()) { glInvalidateFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(attachments.size()), &attachments[0]); } else { glDiscardFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLsizei>(attachments.size()), &attachments[0]); } re.BindFramebuffer(old_fbo); } else { this->Clear(flags, Color(0, 0, 0, 0), 1, 0); } }
// 渲染 ///////////////////////////////////////////////////////////////////////////////// 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 OGLESRenderLayout::Active(ShaderObjectPtr const & so) const { if (use_vao_) { GLuint vao; auto iter = vaos_.find(so); if (iter == vaos_.end()) { glGenVertexArrays(1, &vao); glBindVertexArray(vao); vaos_.emplace(so, vao); this->BindVertexStreams(so); } else { vao = iter->second; glBindVertexArray(vao); if (streams_dirty_) { this->BindVertexStreams(so); streams_dirty_ = false; } } OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); if (this->NumVertexStreams() > 0) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->GetVertexStream(this->NumVertexStreams() - 1))); re.OverrideBindBufferCache(stream.GLType(), stream.GLvbo()); } if (this->InstanceStream() && (glloader_GLES_VERSION_3_0() || glloader_GLES_EXT_instanced_arrays())) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->InstanceStream())); re.OverrideBindBufferCache(stream.GLType(), stream.GLvbo()); } if (this->UseIndices()) { if (re.HackForMali() || re.HackForAdreno()) { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->GetIndexStream())); BOOST_ASSERT(GL_ELEMENT_ARRAY_BUFFER == stream.GLType()); stream.Active(use_vao_); } else { OGLESGraphicsBuffer& stream(*checked_pointer_cast<OGLESGraphicsBuffer>(this->GetIndexStream())); BOOST_ASSERT(GL_ELEMENT_ARRAY_BUFFER == stream.GLType()); re.OverrideBindBufferCache(stream.GLType(), stream.GLvbo()); } } else { re.OverrideBindBufferCache(GL_ELEMENT_ARRAY_BUFFER, 0); } } else { this->BindVertexStreams(so); } }
void OGLESFrameBuffer::Clear(uint32_t flags, Color const & clr, float depth, int32_t stencil) { OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); GLuint old_fbo = re.BindFramebuffer(); re.BindFramebuffer(fbo_); DepthStencilStateDesc const & ds_desc = re.CurDSSObj()->GetDesc(); BlendStateDesc const & blend_desc = re.CurBSObj()->GetDesc(); if (flags & CBM_Color) { if (blend_desc.color_write_mask[0] != CMASK_All) { glColorMask(true, true, true, true); } } if (flags & CBM_Depth) { if (!ds_desc.depth_write_mask) { glDepthMask(GL_TRUE); } } if (flags & CBM_Stencil) { if (!ds_desc.front_stencil_write_mask) { glStencilMaskSeparate(GL_FRONT, GL_TRUE); } if (!ds_desc.back_stencil_write_mask) { glStencilMaskSeparate(GL_BACK, GL_TRUE); } } if (glloader_GLES_VERSION_3_0()) { if (flags & CBM_Color) { if (fbo_ != 0) { for (size_t i = 0; i < clr_views_.size(); ++ i) { if (clr_views_[i]) { glClearBufferfv(GL_COLOR, static_cast<GLint>(i), &clr[0]); } } } else { glClearBufferfv(GL_COLOR, 0, &clr[0]); } } if ((flags & CBM_Depth) && (flags & CBM_Stencil)) { glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil); } else { if (flags & CBM_Depth) { glClearBufferfv(GL_DEPTH, 0, &depth); } else { if (flags & CBM_Stencil) { GLint s = stencil; glClearBufferiv(GL_STENCIL, 0, &s); } } } } else { GLbitfield ogl_flags = 0; if (flags & CBM_Color) { ogl_flags |= GL_COLOR_BUFFER_BIT; re.ClearColor(clr.r(), clr.g(), clr.b(), clr.a()); } if (flags & CBM_Depth) { ogl_flags |= GL_DEPTH_BUFFER_BIT; re.ClearDepth(depth); } if (flags & CBM_Stencil) { ogl_flags |= GL_STENCIL_BUFFER_BIT; re.ClearStencil(stencil); } glClear(ogl_flags); } if (flags & CBM_Color) { if (blend_desc.color_write_mask[0] != CMASK_All) { glColorMask((blend_desc.color_write_mask[0] & CMASK_Red) != 0, (blend_desc.color_write_mask[0] & CMASK_Green) != 0, (blend_desc.color_write_mask[0] & CMASK_Blue) != 0, (blend_desc.color_write_mask[0] & CMASK_Alpha) != 0); } } if (flags & CBM_Depth) { if (!ds_desc.depth_write_mask) { glDepthMask(GL_FALSE); } } if (flags & CBM_Stencil) { if (!ds_desc.front_stencil_write_mask) { glStencilMaskSeparate(GL_FRONT, GL_FALSE); } if (!ds_desc.back_stencil_write_mask) { glStencilMaskSeparate(GL_BACK, GL_FALSE); } } re.BindFramebuffer(old_fbo); }
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_); } }
void OGLESTexture2D::CopyToSubTexture2D(Texture& target, uint32_t dst_array_index, uint32_t dst_level, uint32_t dst_x_offset, uint32_t dst_y_offset, uint32_t dst_width, uint32_t dst_height, uint32_t src_array_index, uint32_t src_level, uint32_t src_x_offset, uint32_t src_y_offset, uint32_t src_width, uint32_t src_height) { BOOST_ASSERT(type_ == target.Type()); OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); if (glloader_GLES_VERSION_3_0() && ((sample_count_ > 1) && !IsCompressedFormat(format_) && (glloader_GLES_EXT_texture_rg() || (4 == NumComponents(format_))))) { GLuint fbo_src, fbo_dst; re.GetFBOForBlit(fbo_src, fbo_dst); GLuint old_fbo = re.BindFramebuffer(); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_src); if (array_size_ > 1) { glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_, src_level, src_array_index); } else { if (sample_count_ <= 1) { glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target_type_, texture_, src_level); } else { glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, texture_); } } OGLESTexture& ogl_target = *checked_cast<OGLESTexture*>(&target); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_dst); if (array_size_ > 1) { glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ogl_target.GLTexture(), dst_level, dst_array_index); } else { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ogl_target.GLType(), ogl_target.GLTexture(), dst_level); } glBlitFramebuffer(src_x_offset, src_y_offset, src_x_offset + src_width, src_y_offset + src_height, dst_x_offset, dst_y_offset, dst_x_offset + dst_width, dst_y_offset + dst_height, GL_COLOR_BUFFER_BIT, ((src_width == dst_width) && (src_height == dst_height)) ? GL_NEAREST : GL_LINEAR); re.BindFramebuffer(old_fbo, true); } else if ((src_width == dst_width) && (src_height == dst_height) && (format_ == target.Format())) { GLint gl_internalFormat; GLenum gl_format; GLenum gl_type; OGLESMapping::MappingFormat(gl_internalFormat, gl_format, gl_type, format_); GLint gl_target_internal_format; GLenum gl_target_format; GLenum gl_target_type; OGLESMapping::MappingFormat(gl_target_internal_format, gl_target_format, gl_target_type, target.Format()); if (IsCompressedFormat(format_)) { BOOST_ASSERT((src_width == dst_width) && (src_height == dst_height)); BOOST_ASSERT((0 == (src_x_offset & 0x3)) && (0 == (src_y_offset & 0x3))); BOOST_ASSERT((0 == (dst_x_offset & 0x3)) && (0 == (dst_y_offset & 0x3))); BOOST_ASSERT((0 == (src_width & 0x3)) && (0 == (src_height & 0x3))); BOOST_ASSERT((0 == (dst_width & 0x3)) && (0 == (dst_height & 0x3))); Texture::Mapper mapper_src(*this, src_array_index, src_level, TMA_Read_Only, src_x_offset, src_y_offset, src_width, src_height); Texture::Mapper mapper_dst(target, dst_array_index, dst_level, TMA_Write_Only, dst_x_offset, dst_y_offset, dst_width, dst_height); uint32_t const block_size = NumFormatBytes(format_) * 4; uint8_t const * s = mapper_src.Pointer<uint8_t>(); uint8_t* d = mapper_dst.Pointer<uint8_t>(); for (uint32_t y = 0; y < src_height; y += 4) { std::memcpy(d, s, src_width / 4 * block_size); s += mapper_src.RowPitch(); d += mapper_dst.RowPitch(); } } else { size_t const format_size = NumFormatBytes(format_); Texture::Mapper mapper_src(*this, src_array_index, src_level, TMA_Read_Only, src_x_offset, src_y_offset, src_width, src_height); Texture::Mapper mapper_dst(target, dst_array_index, dst_level, TMA_Write_Only, dst_x_offset, dst_y_offset, dst_width, dst_height); uint8_t const * s = mapper_src.Pointer<uint8_t>(); uint8_t* d = mapper_dst.Pointer<uint8_t>(); for (uint32_t y = 0; y < src_height; ++ y) { std::memcpy(d, s, src_width * format_size); s += mapper_src.RowPitch(); d += mapper_dst.RowPitch(); } } } else { this->ResizeTexture2D(target, dst_array_index, dst_level, dst_x_offset, dst_y_offset, dst_width, dst_height, src_array_index, src_level, src_x_offset, src_y_offset, src_width, src_height, true); } }
void OGLESTexture3D::Unmap3D(uint32_t array_index, uint32_t level) { BOOST_ASSERT(0 == array_index); KFL_UNUSED(array_index); switch (last_tma_) { case TMA_Read_Only: break; case TMA_Write_Only: case TMA_Read_Write: { GLint gl_internalFormat; GLenum gl_format; GLenum gl_type; OGLESMapping::MappingFormat(gl_internalFormat, gl_format, gl_type, format_); uint32_t const w = this->Width(level); uint32_t const h = this->Height(level); uint32_t const d = this->Depth(level); OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); re.BindTexture(0, target_type_, texture_); if (IsCompressedFormat(format_)) { uint32_t const block_size = NumFormatBytes(format_) * 4; GLsizei const image_size = ((w + 3) / 4) * ((h + 3) / 4) * d * block_size; if (glloader_GLES_VERSION_3_0()) { glCompressedTexSubImage3D(target_type_, level, 0, 0, 0, w, h, d, gl_format, image_size, &tex_data_[level][0]); } else { glCompressedTexSubImage3DOES(target_type_, level, 0, 0, 0, w, h, d, gl_format, image_size, &tex_data_[level][0]); } } else { if (glloader_GLES_VERSION_3_0()) { glTexSubImage3D(target_type_, level, 0, 0, 0, w, h, d, gl_format, gl_type, &tex_data_[level][0]); } else { glTexSubImage3DOES(target_type_, level, 0, 0, 0, w, h, d, gl_format, gl_type, &tex_data_[level][0]); } } } break; default: BOOST_ASSERT(false); break; } }
void OGLESTexture3D::CreateHWResource(ElementInitData const * init_data) { uint32_t texel_size = NumFormatBytes(format_); GLint glinternalFormat; GLenum glformat; GLenum gltype; OGLESMapping::MappingFormat(glinternalFormat, glformat, gltype, format_); glBindTexture(target_type_, texture_); for (uint32_t level = 0; level < num_mip_maps_; ++ level) { uint32_t const w = this->Width(level); uint32_t const h = this->Height(level); uint32_t const d = this->Depth(level); if (IsCompressedFormat(format_)) { uint32_t const block_size = NumFormatBytes(format_) * 4; GLsizei const image_size = ((w + 3) / 4) * ((h + 3) / 4) * d * block_size; void* ptr; if (nullptr == init_data) { tex_data_[level].resize(image_size, 0); ptr = nullptr; } else { tex_data_[level].resize(image_size); std::memcpy(&tex_data_[level][0], init_data[level].data, image_size); ptr = &tex_data_[level][0]; } if (glloader_GLES_VERSION_3_0()) { glCompressedTexImage3D(target_type_, level, glinternalFormat, w, h, d, 0, image_size, ptr); } else { glCompressedTexImage3DOES(target_type_, level, glinternalFormat, w, h, d, 0, image_size, ptr); } } else { GLsizei const image_size = w * h * d * texel_size; void* ptr; if (nullptr == init_data) { tex_data_[level].resize(image_size, 0); ptr = nullptr; } else { tex_data_[level].resize(image_size); std::memcpy(&tex_data_[level][0], init_data[level].data, image_size); ptr = &tex_data_[level][0]; } if (glloader_GLES_VERSION_3_0()) { glTexImage3D(target_type_, level, glinternalFormat, w, h, d, 0, glformat, gltype, ptr); } else { glTexImage3DOES(target_type_, level, glinternalFormat, w, h, d, 0, glformat, gltype, ptr); } } } hw_res_ready_ = true; }
void OGLESTextureCube::CopyToSubTextureCube(Texture& target, uint32_t dst_array_index, CubeFaces dst_face, uint32_t dst_level, uint32_t dst_x_offset, uint32_t dst_y_offset, uint32_t dst_width, uint32_t dst_height, uint32_t src_array_index, CubeFaces src_face, uint32_t src_level, uint32_t src_x_offset, uint32_t src_y_offset, uint32_t src_width, uint32_t src_height) { BOOST_ASSERT(type_ == target.Type()); OGLESRenderEngine& re = *checked_cast<OGLESRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); if (glloader_GLES_VERSION_3_0() && (!IsCompressedFormat(format_) && (glloader_GLES_EXT_texture_rg() || (4 == NumComponents(format_))))) { GLuint fbo_src, fbo_dst; re.GetFBOForBlit(fbo_src, fbo_dst); GLuint old_fbo = re.BindFramebuffer(); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_src); if (array_size_ > 1) { glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_, src_level, src_array_index * 6 + src_face - CF_Positive_X); } else { glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + src_face - CF_Positive_X, texture_, src_level); } glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_dst); if (target.ArraySize() > 1) { glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, checked_cast<OGLESTexture*>(&target)->GLTexture(), dst_level, dst_array_index * 6 + dst_face - CF_Positive_X); } else { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + dst_face - CF_Positive_X, checked_cast<OGLESTexture*>(&target)->GLTexture(), dst_level); } glBlitFramebuffer(src_x_offset, src_y_offset, src_x_offset + src_width, src_y_offset + src_height, dst_x_offset, dst_y_offset, dst_x_offset + dst_width, dst_y_offset + dst_height, GL_COLOR_BUFFER_BIT, ((src_width == dst_width) && (src_height == dst_height)) ? GL_NEAREST : GL_LINEAR); re.BindFramebuffer(old_fbo, true); } else { if ((src_width == dst_width) && (src_height == dst_height) && (format_ == target.Format())) { if (IsCompressedFormat(format_)) { BOOST_ASSERT((0 == (src_x_offset & 0x3)) && (0 == (src_y_offset & 0x3))); BOOST_ASSERT((0 == (dst_x_offset & 0x3)) && (0 == (dst_y_offset & 0x3))); BOOST_ASSERT((0 == (src_width & 0x3)) && (0 == (src_height & 0x3))); BOOST_ASSERT((0 == (dst_width & 0x3)) && (0 == (dst_height & 0x3))); Texture::Mapper mapper_src(*this, src_array_index, src_face, src_level, TMA_Read_Only, 0, 0, this->Width(src_level), this->Height(src_level)); Texture::Mapper mapper_dst(target, dst_array_index, dst_face, dst_level, TMA_Write_Only, 0, 0, target.Width(dst_level), target.Height(dst_level)); uint32_t const block_size = NumFormatBytes(format_) * 4; uint8_t const * s = mapper_src.Pointer<uint8_t>() + (src_y_offset / 4) * mapper_src.RowPitch() + (src_x_offset / 4 * block_size); uint8_t* d = mapper_dst.Pointer<uint8_t>() + (dst_y_offset / 4) * mapper_dst.RowPitch() + (dst_x_offset / 4 * block_size); for (uint32_t y = 0; y < src_height; y += 4) { std::memcpy(d, s, src_width / 4 * block_size); s += mapper_src.RowPitch(); d += mapper_dst.RowPitch(); } } else { size_t const format_size = NumFormatBytes(format_); Texture::Mapper mapper_src(*this, src_array_index, src_face, src_level, TMA_Read_Only, src_x_offset, src_y_offset, src_width, src_height); Texture::Mapper mapper_dst(target, dst_array_index, dst_face, dst_level, TMA_Write_Only, dst_x_offset, dst_y_offset, dst_width, dst_height); uint8_t const * s = mapper_src.Pointer<uint8_t>(); uint8_t* d = mapper_dst.Pointer<uint8_t>(); for (uint32_t y = 0; y < src_height; ++ y) { std::memcpy(d, s, src_width * format_size); s += mapper_src.RowPitch(); d += mapper_dst.RowPitch(); } } } else { this->ResizeTextureCube(target, dst_array_index, dst_face, dst_level, dst_x_offset, dst_y_offset, dst_width, dst_height, src_array_index, src_face, src_level, src_x_offset, src_y_offset, src_width, src_height, true); } } }
OGLESTextureCube::OGLESTextureCube(uint32_t size, uint32_t numMipMaps, uint32_t array_size, ElementFormat format, uint32_t sample_count, uint32_t sample_quality, uint32_t access_hint, ElementInitData const * init_data) : OGLESTexture(TT_Cube, array_size, sample_count, sample_quality, access_hint) { if (IsSRGB(format)) { format = this->SRGBToRGB(format); } format_ = format; if (0 == numMipMaps) { num_mip_maps_ = 1; uint32_t s = size; while (s > 1) { ++ num_mip_maps_; s = std::max<uint32_t>(1U, s / 2); } } else { num_mip_maps_ = numMipMaps; } array_size_ = 1; uint32_t texel_size = NumFormatBytes(format_); GLint glinternalFormat; GLenum glformat; GLenum gltype; OGLESMapping::MappingFormat(glinternalFormat, glformat, gltype, format_); glGenTextures(1, &texture_); glBindTexture(target_type_, texture_); glTexParameteri(target_type_, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(target_type_, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if (glloader_GLES_VERSION_3_0()) { glTexParameteri(target_type_, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL, num_mip_maps_ - 1); } else if (glloader_GLES_APPLE_texture_max_level()) { glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL_APPLE, num_mip_maps_ - 1); } tex_data_.resize(6 * num_mip_maps_); widths_.resize(6 * num_mip_maps_); for (int face = 0; face < 6; ++ face) { uint32_t s = size; for (uint32_t level = 0; level < num_mip_maps_; ++ level) { widths_[face * num_mip_maps_ + level] = s; if (IsCompressedFormat(format_)) { int block_size; if ((EF_BC1 == format_) || (EF_SIGNED_BC1 == format_) || (EF_BC1_SRGB == format_) || (EF_BC4 == format_) || (EF_SIGNED_BC4 == format_) || (EF_BC4_SRGB == format_)) { block_size = 8; } else { block_size = 16; } GLsizei const image_size = ((s + 3) / 4) * ((s + 3) / 4) * block_size; if (nullptr == init_data) { tex_data_[face * num_mip_maps_ + level].resize(image_size, 0); } else { tex_data_[face * num_mip_maps_ + level].resize(image_size); std::memcpy(&tex_data_[face * num_mip_maps_ + level][0], init_data[face * num_mip_maps_ + level].data, image_size); } glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, glinternalFormat, s, s, 0, image_size, &tex_data_[face * num_mip_maps_ + level][0]); } else { GLsizei const image_size = s * s * texel_size; if (nullptr == init_data) { tex_data_[face * num_mip_maps_ + level].resize(image_size, 0); } else { tex_data_[face * num_mip_maps_ + level].resize(image_size); std::memcpy(&tex_data_[face * num_mip_maps_ + level][0], init_data[face * num_mip_maps_ + level].data, image_size); } glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, glinternalFormat, s, s, 0, glformat, gltype, &tex_data_[face * num_mip_maps_ + level][0]); } s = std::max(1U, s / 2); } } }