void TUniform::Animate(int period) { if (!duration) return; elapsed += period; while (elapsed > duration) elapsed -= duration; int total = 0; for (TMotionList::iterator i = motions.begin(); i != motions.end(); ++i) { if (elapsed < total + i->duration) { int numFloatComponents = 0; int numIntComponents = 0; if (IsInteger()) numIntComponents = NumComponents(); else numFloatComponents = NumComponents(); // // All three progressions satisfy these conditions: // // f(0) = start // f(length) = stop // // Linear: f(t) = start + t * (stop - start) / length; // Exponential: f(t) = TBD // Logarithmic: f(t) = TBD // if (i->type == Linear) { for (int c = 0; c < numFloatComponents; ++c) { float start = i->start.f[c]; float stop = i->stop.f[c]; value.f[c] = start + (float) (elapsed - total) * (stop - start) / i->duration; } for (int c = 0; c < numIntComponents; ++c) { int start = i->start.i[c]; int stop = i->stop.i[c]; float f = (float) (elapsed - total) * (float) (stop - start) / i->duration; value.i[c] = start + (int) f; } } else if (i->type == Exponential) { wxGetApp().Errorf("Exponential motion is not yet implemented."); } else if (i->type == Logarithmic) { wxGetApp().Errorf("Logarthmic motion is not yet implemented."); } else { wxGetApp().Errorf("Unknown motion type."); } break; } total += i->duration; } }
void TUniform::UpdateSlider() { if (!slider.IsValid()) return; if (IsInteger()) { for (int c = 0; c < NumComponents(); ++c) value.i[c] = slider.current.i[c]; } else { for (int c = 0; c < NumComponents(); ++c) value.f[c] = slider.current.f[c]; } }
Spectrum BSDF::Sample_f(const Vector3f &woWorld, Vector3f *wiWorld, const Point2f &u, Float *pdf, BxDFType type, BxDFType *sampledType) const { ProfilePhase pp(Prof::BSDFEvaluation); // Choose which _BxDF_ to sample int matchingComps = NumComponents(type); if (matchingComps == 0) { *pdf = 0; if (sampledType) *sampledType = BxDFType(0); return Spectrum(0); } int comp = std::min((int)std::floor(u[0] * matchingComps), matchingComps - 1); // Get _BxDF_ pointer for chosen component BxDF *bxdf = nullptr; int count = comp; for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i]->MatchesFlags(type) && count-- == 0) { bxdf = bxdfs[i]; break; } Assert(bxdf); // Remap _BxDF_ sample _u_ to $[0,1)^2$ Point2f uRemapped(u[0] * matchingComps - comp, u[1]); // Sample chosen _BxDF_ Vector3f wi, wo = WorldToLocal(woWorld); *pdf = 0; if (sampledType) *sampledType = bxdf->type; Spectrum f = bxdf->Sample_f(wo, &wi, uRemapped, pdf, sampledType); if (*pdf == 0) { if (sampledType) *sampledType = BxDFType(0); return 0; } *wiWorld = LocalToWorld(wi); // Compute overall PDF with all matching _BxDF_s if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1) for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i] != bxdf && bxdfs[i]->MatchesFlags(type)) *pdf += bxdfs[i]->Pdf(wo, wi); if (matchingComps > 1) *pdf /= matchingComps; // Compute value of BSDF for sampled direction if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1) { bool reflect = Dot(*wiWorld, ng) * Dot(woWorld, ng) > 0; f = 0.; for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i]->MatchesFlags(type) && ((reflect && (bxdfs[i]->type & BSDF_REFLECTION)) || (!reflect && (bxdfs[i]->type & BSDF_TRANSMISSION)))) f += bxdfs[i]->f(wo, wi); } return f; }
Spectrum BSDF::Sample_f(const Vector &woW, Vector *wiW, float u1, float u2, float u3, float *pdf, BxDFType flags, BxDFType *sampledType) const { // Choose which _BxDF_ to sample int matchingComps = NumComponents(flags); if (matchingComps == 0) { *pdf = 0.f; return Spectrum(0.f); } int which = min(Floor2Int(u3 * matchingComps), matchingComps-1); BxDF *bxdf = NULL; int count = which; for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i]->MatchesFlags(flags)) if (count-- == 0) { bxdf = bxdfs[i]; break; } Assert(bxdf); // NOBOOK // Sample chosen _BxDF_ Vector wi; Vector wo = WorldToLocal(woW); *pdf = 0.f; Spectrum f = bxdf->Sample_f(wo, &wi, u1, u2, pdf); if (*pdf == 0.f) return 0.f; if (sampledType) *sampledType = bxdf->type; *wiW = LocalToWorld(wi); // Compute overall PDF with all matching _BxDF_s if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1) { for (int i = 0; i < nBxDFs; ++i) { if (bxdfs[i] != bxdf && bxdfs[i]->MatchesFlags(flags)) *pdf += bxdfs[i]->Pdf(wo, wi); } } if (matchingComps > 1) *pdf /= matchingComps; // Compute value of BSDF for sampled direction if (!(bxdf->type & BSDF_SPECULAR)) { f = 0.; if (Dot(*wiW, ng) * Dot(woW, ng) > 0) // ignore BTDFs flags = BxDFType(flags & ~BSDF_TRANSMISSION); else // ignore BRDFs flags = BxDFType(flags & ~BSDF_REFLECTION); for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i]->MatchesFlags(flags)) f += bxdfs[i]->f(wo, wi); } return f; }
void Texture::WriteTGA(const std::string& filename) { unsigned sz = NumComponents(_internalFormat) * _width * _height; COM::byte_t* pixels = new COM::byte_t[sz]; glPixelStorei(GL_PACK_ALIGNMENT, 1); Bind(0); GL_CALL(glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, pixels)); WriteTGA_BGR(filename, (unsigned short)_width, (unsigned short)_height, pixels); delete[] pixels; }
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 Texture::Init(const COM::byte_t* pixelData) { COM_assert(0 < _width); COM_assert(0 < _height); GL_CALL(glGenTextures(1, &_id)); GL_CALL(glBindTexture(GL_TEXTURE_2D, _id)); GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, _internalFormat, _width, _height, 0, _format, GL_UNSIGNED_BYTE, pixelData)); metrics.resources.totalTextureBufferSize += sizeof(char) * NumComponents(_internalFormat) * _width * _height; GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)); if(GL_DEPTH_COMPONENT == _format) { // TODO: you probably don't want this for every depth texture... GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_ALPHA)); } }
void MotionPlannerInterface::GetStats(PropertyMap& stats) const { stats.set("numIters",NumIterations()); stats.set("numMilestones",NumMilestones()); stats.set("numComponents",NumComponents()); }
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); } } }
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 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::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 OGLTexture1D::CopyToSubTexture1D(Texture& target, uint32_t dst_array_index, uint32_t dst_level, uint32_t dst_x_offset, uint32_t dst_width, uint32_t src_array_index, uint32_t src_level, uint32_t src_x_offset, uint32_t src_width) { BOOST_ASSERT(type_ == target.Type()); if ((format_ == target.Format()) && !IsCompressedFormat(format_) && (glloader_GL_VERSION_4_3() || glloader_GL_ARB_copy_image()) && (src_width == dst_width) && (1 == sample_count_)) { OGLTexture& ogl_target = *checked_cast<OGLTexture*>(&target); glCopyImageSubData( texture_, target_type_, src_level, src_x_offset, 0, src_array_index, ogl_target.GLTexture(), ogl_target.GLType(), dst_level, dst_x_offset, 0, dst_array_index, src_width, 1, 1); } else { OGLRenderEngine& re = *checked_cast<OGLRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); if ((sample_count_ > 1) && !IsCompressedFormat(format_) && (glloader_GL_ARB_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) { glFramebufferTexture1D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target_type_, texture_, src_level); } else { glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, texture_); } } OGLTexture& ogl_target = *checked_cast<OGLTexture*>(&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 { glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target_type_, ogl_target.GLTexture(), dst_level); } glBlitFramebuffer(src_x_offset, 0, src_x_offset + src_width, 1, dst_x_offset, 0, dst_x_offset + dst_width, 1, GL_COLOR_BUFFER_BIT, (src_width == dst_width) ? GL_NEAREST : GL_LINEAR); re.BindFramebuffer(old_fbo, true); } else { if ((src_width == dst_width) && (format_ == target.Format())) { if (IsCompressedFormat(format_)) { BOOST_ASSERT(0 == (src_x_offset & 0x3)); BOOST_ASSERT(0 == (dst_x_offset & 0x3)); BOOST_ASSERT(0 == (src_width & 0x3)); BOOST_ASSERT(0 == (dst_width & 0x3)); Texture::Mapper mapper_src(*this, src_array_index, src_level, TMA_Read_Only, 0, this->Width(src_level)); Texture::Mapper mapper_dst(target, dst_array_index, dst_level, TMA_Write_Only, 0, target.Width(dst_level)); uint32_t const block_size = NumFormatBytes(format_) * 4; uint8_t const * s = mapper_src.Pointer<uint8_t>() + (src_x_offset / 4 * block_size); uint8_t* d = mapper_dst.Pointer<uint8_t>() + (dst_x_offset / 4 * block_size); std::memcpy(d, s, src_width / 4 * block_size); } 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_width); Texture::Mapper mapper_dst(target, dst_array_index, dst_level, TMA_Write_Only, dst_x_offset, dst_width); uint8_t const * s = mapper_src.Pointer<uint8_t>(); uint8_t* d = mapper_dst.Pointer<uint8_t>(); std::memcpy(d, s, src_width * format_size); } } else { this->ResizeTexture1D(target, dst_array_index, dst_level, dst_x_offset, dst_width, src_array_index, src_level, src_x_offset, src_width, true); } } } }
RGB BSDF::Sample_f(const Vector &woWorld, Vector *wiWorld, const BSDFSample &bsdfSample, float *pdf, BxDFType flags, BxDFType *sampledType) const { int numComp = NumComponents(flags); if (numComp == 0) { *pdf = 0; if (sampledType) *sampledType = BxDFType(0); return 0; } int whichComp = min(Floor2Int(bsdfSample.uComponent * numComp), numComp - 1); int count = whichComp; BxDF *bxdf = nullptr; //被选中的Bxdf for (int i = 0; i < mNumBxdf; ++i) { if (mBxdfs[i]->MatchesFlag(flags) && count-- == 0) { //这技巧 GOOD bxdf = mBxdfs[i]; break; } } Vector wo = WorldToLocal(woWorld); //获得局部坐标下的wo Vector wi; *pdf = 0.f; RGB f = bxdf->Sample_f(wo, &wi, bsdfSample.uDir[0], bsdfSample.uDir[1], pdf); //这里的主要作用是采样出射方向 if (*pdf == 0) { if (sampledType) *sampledType = BxDFType(0); return 0; } if (sampledType) *sampledType = bxdf->type; *wiWorld = LocalToWorld(wi); //获得世界坐标系下的wi //计算pdf if (!(bxdf->type & BSDF_SPECULAR) && numComp > 1) { for (int i = 0; i < mNumBxdf; ++i) { if (bxdf != mBxdfs[i] && mBxdfs[i]->MatchesFlag(flags)) { *pdf += mBxdfs[i]->Pdf(wo, wi); } } } if (numComp > 1) { *pdf /= numComp; } //开始计算BRDF系数 if (!(bxdf->type & BSDF_SPECULAR)) { f=0;//因为不是镜面反射 所以重新计算BRDF if (Dot(*wiWorld, mNG) * Dot(woWorld, mNG) > 0) //反射 flags = BxDFType(flags & ~BSDF_TRANSMISSION); else//折射 flags = BxDFType(flags & ~BSDF_REFLECTION); for (int i = 0; i < mNumBxdf; ++i) if (mBxdfs[i]->MatchesFlag(flags)) f += mBxdfs[i]->f(wo, wi); } return f; }
bool WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const { const auto& linkInfo = mMostRecentLinkInfo; const auto& gl = mContext->gl; // Check if the attrib name conflicting to uniform name for (const auto& attrib : linkInfo->attribs) { const auto& attribName = attrib.mActiveInfo->mBaseUserName; for (const auto& uniform : linkInfo->uniforms) { const auto& uniformName = uniform->mActiveInfo->mBaseUserName; if (attribName == uniformName) { *out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:" " %s", attribName.BeginReading()); return false; } } } std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc; for (const auto& attrib : linkInfo->attribs) { const auto& elemType = attrib.mActiveInfo->mElemType; const auto numUsedLocs = NumUsedLocationsByElemType(elemType); for (uint32_t i = 0; i < numUsedLocs; i++) { const uint32_t usedLoc = attrib.mLoc + i; const auto res = attribsByLoc.insert({usedLoc, &attrib}); const bool& didInsert = res.second; if (!didInsert) { const auto& aliasingName = attrib.mActiveInfo->mBaseUserName; const auto& itrExisting = res.first; const auto& existingInfo = itrExisting->second; const auto& existingName = existingInfo->mActiveInfo->mBaseUserName; *out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by" " attrib \"%s\".", aliasingName.BeginReading(), existingName.BeginReading()); return false; } } } // Forbid: // * Unrecognized varying name // * Duplicate varying name // * Too many components for specified buffer mode if (mNextLink_TransformFeedbackVaryings.size()) { GLuint maxComponentsPerIndex = 0; switch (mNextLink_TransformFeedbackBufferMode) { case LOCAL_GL_INTERLEAVED_ATTRIBS: gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &maxComponentsPerIndex); break; case LOCAL_GL_SEPARATE_ATTRIBS: gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &maxComponentsPerIndex); break; default: MOZ_CRASH("`bufferMode`"); } std::vector<size_t> componentsPerVert; std::set<const WebGLActiveInfo*> alreadyUsed; for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) { if (!componentsPerVert.size() || mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS) { componentsPerVert.push_back(0); } //// const WebGLActiveInfo* curInfo = nullptr; for (const auto& info : linkInfo->transformFeedbackVaryings) { const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName); if (info_wideUserName == wideUserName) { curInfo = info.get(); break; } } if (!curInfo) { const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName); *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not" " found.", asciiUserName.BeginReading()); return false; } const auto insertResPair = alreadyUsed.insert(curInfo); const auto& didInsert = insertResPair.second; if (!didInsert) { const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName); *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\"" " specified twice.", asciiUserName.BeginReading()); return false; } //// size_t varyingComponents = NumComponents(curInfo->mElemType); varyingComponents *= curInfo->mElemCount; auto& totalComponentsForIndex = *(componentsPerVert.rbegin()); totalComponentsForIndex += varyingComponents; if (totalComponentsForIndex > maxComponentsPerIndex) { const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName); *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\"" " pushed `componentsForIndex` over the" " limit of %u.", asciiUserName.BeginReading(), maxComponentsPerIndex); return false; } } linkInfo->componentsPerTFVert.swap(componentsPerVert); } return true; }
Texture::~Texture() { GL_CALL(glDeleteTextures(1, &_id)); metrics.resources.totalTextureBufferSize -= sizeof(char) * NumComponents(_internalFormat) * _width * _height; }
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); } }