diff options
Diffstat (limited to 'o3d/command_buffer/service/texture_gl.cc')
-rw-r--r-- | o3d/command_buffer/service/texture_gl.cc | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/o3d/command_buffer/service/texture_gl.cc b/o3d/command_buffer/service/texture_gl.cc new file mode 100644 index 0000000..954a007 --- /dev/null +++ b/o3d/command_buffer/service/texture_gl.cc @@ -0,0 +1,766 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the texture-related GAPI functions on GL. + +#include "command_buffer/service/gapi_gl.h" +#include "command_buffer/service/texture_gl.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +// Gets the GL internal format, format and type corresponding to a command +// buffer texture format. +bool GetGLFormatType(texture::Format format, + GLenum *internal_format, + GLenum *gl_format, + GLenum *gl_type) { + switch (format) { + case texture::kXRGB8: { + *internal_format = GL_RGB; + *gl_format = GL_BGRA; + *gl_type = GL_UNSIGNED_BYTE; + break; + } + case texture::kARGB8: { + *internal_format = GL_RGBA; + *gl_format = GL_BGRA; + *gl_type = GL_UNSIGNED_BYTE; + break; + } + case texture::kABGR16F: { + *internal_format = GL_RGBA16F_ARB; + *gl_format = GL_RGBA; + *gl_type = GL_HALF_FLOAT_ARB; + break; + } + case texture::kR32F: { + *internal_format = GL_LUMINANCE32F_ARB; + *gl_format = GL_LUMINANCE; + *gl_type = GL_FLOAT; + break; + } + case texture::kABGR32F: { + *internal_format = GL_RGBA32F_ARB; + *gl_format = GL_BGRA; + *gl_type = GL_FLOAT; + break; + } + case texture::kDXT1: { + *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + *gl_format = 0; + *gl_type = 0; + break; + } + // TODO(petersont): Add DXT3/5 support. + default: + return false; + } + + return true; +} + +// Helper class used to prepare image data to match the layout that +// glTexImage* and glCompressedTexImage* expect. +class SetImageHelper { + public: + SetImageHelper() + : buffer_(NULL), + image_data_(NULL), + image_size_(0) { + } + + // Initializes the helper with the input data, re-using the input buffer if + // possible, or copying it into a temporary one. + bool Initialize(const MipLevelInfo &mip_info, + const Volume& volume, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int src_size, + const void *data) { + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || + src_size < src_transfer_info.total_size) + return false; + if (!src_transfer_info.packed) { + TransferInfo dst_transfer_info; + MakePackedTransferInfo(&dst_transfer_info, mip_info, volume); + buffer_.reset(new unsigned char[dst_transfer_info.total_size]); + TransferVolume(volume, mip_info, dst_transfer_info, buffer_.get(), + src_transfer_info, data); + image_data_ = buffer_.get(); + image_size_ = dst_transfer_info.total_size; + } else { + image_data_ = data; + image_size_ = src_transfer_info.total_size; + } + return true; + } + + // Gets the buffer that contains the data in the GL format. + const void *image_data() { return image_data_; } + // Gets the size of the buffer as GL expects it. + unsigned int image_size() { return image_size_; } + + private: + scoped_array<unsigned char> buffer_; + const void *image_data_; + unsigned int image_size_; + DISALLOW_COPY_AND_ASSIGN(SetImageHelper); +}; + +// Helper class used to retrieve image data to match the layout that +// glGetTexImage and glGetCompressedTexImage expect. +class GetImageHelper { + public: + GetImageHelper() + : dst_data_(NULL), + buffer_(NULL), + image_data_(NULL) { + memset(&mip_info_, 0, sizeof(mip_info_)); + memset(&volume_, 0, sizeof(volume_)); + memset(&dst_transfer_info_, 0, sizeof(dst_transfer_info_)); + memset(&src_transfer_info_, 0, sizeof(src_transfer_info_)); + } + + // Initialize the helper to make available a buffer to get the data from GL. + // It will re-use the passed in buffer if the layout matches GL, or allocate + // a temporary one. + bool Initialize(const MipLevelInfo &mip_info, + const Volume& volume, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int dst_size, + void *dst_data) { + mip_info_ = mip_info; + volume_ = volume; + dst_data_ = dst_data; + MakeTransferInfo(&dst_transfer_info_, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || + dst_size < dst_transfer_info_.total_size) + return false; + + if (!IsFullVolume(mip_info, volume) || !dst_transfer_info_.packed) { + // We can only retrieve the full image from GL. + Volume full_volume = { + 0, 0, 0, + mip_info.width, mip_info.height, mip_info.depth + }; + MakePackedTransferInfo(&src_transfer_info_, mip_info, full_volume); + buffer_.reset(new unsigned char[src_transfer_info_.total_size]); + image_data_ = buffer_.get(); + } else { + image_data_ = dst_data; + } + return true; + } + + // Finalize the helper, copying the data into the final buffer if needed. + void Finalize() { + if (!buffer_.get()) return; + unsigned int offset = + volume_.x / mip_info_.block_size_x * mip_info_.block_bpp + + volume_.y / mip_info_.block_size_y * src_transfer_info_.row_pitch + + volume_.z * src_transfer_info_.slice_pitch; + src_transfer_info_.row_size = dst_transfer_info_.row_size; + TransferVolume(volume_, mip_info_, dst_transfer_info_, dst_data_, + src_transfer_info_, buffer_.get() + offset); + } + + // Gets the buffer that can receive the data from GL. + void *image_data() { return image_data_; } + + private: + MipLevelInfo mip_info_; + Volume volume_; + TransferInfo dst_transfer_info_; + TransferInfo src_transfer_info_; + void *dst_data_; + scoped_array<unsigned char> buffer_; + void *image_data_; + DISALLOW_COPY_AND_ASSIGN(GetImageHelper); +}; + +} // anonymous namespace + +TextureGL::~TextureGL() { + glDeleteTextures(1, &gl_texture_); + CHECK_GL_ERROR(); +} + +Texture2DGL *Texture2DGL::Create(unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(width, 0U); + DCHECK_GT(height, 0U); + DCHECK_GT(levels, 0U); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_2D, gl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1); + // glCompressedTexImage2D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, 1, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + memset(buffer.get(), 0, size); + + unsigned int mip_width = width; + unsigned int mip_height = height; + + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, mip_height, + 0, gl_format, gl_type, buffer.get()); + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, 1, i); + unsigned int size = GetMipLevelSize(mip_info); + glCompressedTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, + mip_height, 0, size, buffer.get()); + } + mip_width = std::max(1U, mip_width >> 1); + mip_height = std::max(1U, mip_height >> 1); + } + return new Texture2DGL( + levels, format, enable_render_surfaces, flags, width, height, gl_texture); +} + +// Sets data into a 2D texture resource. +bool Texture2DGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + if (gl_format) { + glTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, volume.width, + volume.height, gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, + volume.width, volume.height, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool Texture2DGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + if (gl_format) { + glGetTexImage(GL_TEXTURE_2D, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(GL_TEXTURE_2D, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +bool Texture2DGL::CreateRenderSurface(int width, + int height, + int mip_level, + int side) { + return false; +} + +bool Texture2DGL::InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) { + ::glFramebufferTexture2DEXT( + GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, + gl_texture_, + gl_surface->mip_level()); + + GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) { + return false; + } + + return true; +} + +Texture3DGL *Texture3DGL::Create(unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(width, 0U); + DCHECK_GT(height, 0U); + DCHECK_GT(depth, 0U); + DCHECK_GT(levels, 0U); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_3D, gl_texture); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, levels - 1); + // glCompressedTexImage3D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, depth, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + memset(buffer.get(), 0, size); + + unsigned int mip_width = width; + unsigned int mip_height = height; + unsigned int mip_depth = depth; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, mip_height, + mip_depth, 0, gl_format, gl_type, buffer.get()); + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, depth, i); + unsigned int size = GetMipLevelSize(mip_info); + glCompressedTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, + mip_height, mip_depth, 0, size, buffer.get()); + } + mip_width = std::max(1U, mip_width >> 1); + mip_height = std::max(1U, mip_height >> 1); + mip_depth = std::max(1U, mip_depth >> 1); + } + return new Texture3DGL(levels, format, enable_render_surfaces, flags, width, + height, depth, gl_texture); +} + +bool Texture3DGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_3D, gl_texture_); + if (gl_format) { + glTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, volume.z, + volume.width, volume.height, volume.depth, + gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, + volume.z, volume.width, volume.height, + volume.depth, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool Texture3DGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_3D, gl_texture_); + if (gl_format) { + glGetTexImage(GL_TEXTURE_3D, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(GL_TEXTURE_3D, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +bool Texture3DGL::CreateRenderSurface(int width, + int height, + int mip_level, + int side) { + return false; +} + +bool Texture3DGL::InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) { + return false; +} + +TextureCubeGL *TextureCubeGL::Create(unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(side, 0U); + DCHECK_GT(levels, 0U); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, + levels-1); + // glCompressedTexImage2D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, side, side, 1, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + memset(buffer.get(), 0, size); + + unsigned int mip_side = side; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + for (unsigned int face = 0; face < 6; ++face) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, + gl_internal_format, mip_side, mip_side, + 0, gl_format, gl_type, buffer.get()); + } + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, side, side, 1, i); + unsigned int size = GetMipLevelSize(mip_info); + for (unsigned int face = 0; face < 6; ++face) { + glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, + gl_internal_format, mip_side, mip_side, 0, size, + buffer.get()); + } + } + mip_side = std::max(1U, mip_side >> 1); + } + return new TextureCubeGL( + levels, format, enable_render_surfaces, flags, side, gl_texture); +} + +// Check that GL_TEXTURE_CUBE_MAP_POSITIVE_X + face yields the correct GLenum. +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveX == + GL_TEXTURE_CUBE_MAP_POSITIVE_X, POSITIVE_X_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeX == + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, NEGATIVE_X_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveY == + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, POSITIVE_Y_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeY == + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, NEGATIVE_Y_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveZ == + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, POSITIVE_Z_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeZ == + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, NEGATIVE_Z_ENUMS_DO_NOT_MATCH); + +bool TextureCubeGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_); + GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (gl_format) { + glTexSubImage2D(face_target, level, volume.x, volume.y, volume.width, + volume.height, gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage2D(face_target, level, volume.x, volume.y, + volume.width, volume.height, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool TextureCubeGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_); + GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (gl_format) { + glGetTexImage(face_target, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(face_target, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +bool TextureCubeGL::CreateRenderSurface(int width, + int height, + int mip_level, + int side) { + return false; +} + +bool TextureCubeGL::InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) { + ::glFramebufferTexture2DEXT( + GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + gl_surface->side(), + gl_texture_, + gl_surface->mip_level()); + + GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) { + return false; + } + + return true; +} + + +// Destroys a texture resource. +parse_error::ParseError GAPIGL::DestroyTexture(ResourceId id) { + // Dirty effect, because this texture id may be used. + DirtyEffect(); + return textures_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Creates a 2D texture resource. +parse_error::ParseError GAPIGL::CreateTexture2D( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + Texture2DGL *texture = Texture2DGL::Create( + width, height, levels, format, flags, enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Creates a 3D texture resource. +parse_error::ParseError GAPIGL::CreateTexture3D( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + Texture3DGL *texture = Texture3DGL::Create( + width, height, depth, levels, format, flags, enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Creates a cube map texture resource. +parse_error::ParseError GAPIGL::CreateTextureCube( + ResourceId id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + TextureCubeGL *texture = TextureCubeGL::Create( + side, levels, format, flags, enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Copies the data into a texture resource. +parse_error::ParseError GAPIGL::SetTextureData( + ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + TextureGL *texture = textures_.Get(id); + if (!texture) + return parse_error::kParseInvalidArguments; + Volume volume = {x, y, z, width, height, depth}; + // Dirty effect: SetData may need to call glBindTexture which will mess up the + // sampler parameters. + DirtyEffect(); + return texture->SetData(volume, level, face, row_pitch, slice_pitch, + size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data from a texture resource. +parse_error::ParseError GAPIGL::GetTextureData( + ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + TextureGL *texture = textures_.Get(id); + if (!texture) + return parse_error::kParseInvalidArguments; + Volume volume = {x, y, z, width, height, depth}; + // Dirty effect: GetData may need to call glBindTexture which will mess up the + // sampler parameters. + DirtyEffect(); + return texture->GetData(volume, level, face, row_pitch, slice_pitch, + size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +} // namespace o3d +} // namespace command_buffer |