summaryrefslogtreecommitdiffstats
path: root/o3d/core/cross/gl
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-03 22:56:18 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-03 22:56:18 +0000
commitaa078b67d3d8e976ffeee26e2dcccb6e938b7008 (patch)
tree3f9edf829005027d107a5f20527a78780386f135 /o3d/core/cross/gl
parent04c2262254185379aa762a69ab4410f3aedab9af (diff)
downloadchromium_src-aa078b67d3d8e976ffeee26e2dcccb6e938b7008.zip
chromium_src-aa078b67d3d8e976ffeee26e2dcccb6e938b7008.tar.gz
chromium_src-aa078b67d3d8e976ffeee26e2dcccb6e938b7008.tar.bz2
Add SetRect to Texture2d and TextureCUBE
Originally I was going to replace Lock/Unlock with only SetRect (and maybe GetRect) and I did that. But then as I was going through the code things started not being so cool. The JavaScript texture.SetRect where as before it allocated no memory, now it needed to allocate a temporary buffer just to be able to write the texture. DrawImage also would have have required copying the original texture out using GetRect, then modifying it, then copying it back even in D3D or it would have required a temporary buffer. That's what happens under the hood in the GL implementation of Texture2D but why should D3D suffer because of the of GL? Or maybe it's a reasonable compomise the D3D should go slower so that GL isn't twice as slow as it it could be? So, I left Lock/Unlock and added SetRect as well. This CL should help the video guys and we can decide if we want to get rid of Lock/Unlock later. SetRect is really only there because trying to make GL act like D3D makes GL slow since we had to get a copy of the texture from GL before Locking. SetRect, since it is not exposing the original data doesn't need to do that. So, now there are both. If need to read (and write) to the texture use Lock. If you only need to write use SetRect. I also fixed Lock/Unlock so they return a pitch which is required for D3D. While I did that I made Lock/Unlock private so you have to use the TextureXXXLockHelpers to access the data. I didn't do the command buffer versions. I also added stubs for texture tests. We need to add more tests. I feel like a lot of clean up needs to happen. It seesm like Bitmap should be split into Bitmap2D BitmapCUBE BitmapVolume Possibly. And maybe BitmapCube should effectively just be typedef Bitmap2D BitmapCUBE[6] and BitmapVolume would be std::vector<Bitmap2D> Then we wouldn't need face and volume versions of various functions. You'd just get the face or the slice Bitma2D and then use the 2D functions. We should decide if that's what we want before pushing a new release. Otherwise we should remove bitmap.idl from idl_scons.lst and the one sample And ship without exposing Bitmap until we are sure they API we are exposing is the one we want. Review URL: http://codereview.chromium.org/159725 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22332 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/core/cross/gl')
-rw-r--r--o3d/core/cross/gl/texture_gl.cc222
-rw-r--r--o3d/core/cross/gl/texture_gl.h45
2 files changed, 247 insertions, 20 deletions
diff --git a/o3d/core/cross/gl/texture_gl.cc b/o3d/core/cross/gl/texture_gl.cc
index f904d3d..ff9588f 100644
--- a/o3d/core/cross/gl/texture_gl.cc
+++ b/o3d/core/cross/gl/texture_gl.cc
@@ -36,6 +36,7 @@
#include "core/cross/precompile.h"
#include "core/cross/error.h"
#include "core/cross/types.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/gl/renderer_gl.h"
#include "core/cross/gl/render_surface_gl.h"
#include "core/cross/gl/texture_gl.h"
@@ -154,11 +155,12 @@ static bool UpdateGLImageFromBitmap(GLenum target,
DCHECK(bitmap.image_data());
unsigned int mip_width = std::max(1U, bitmap.width() >> level);
unsigned int mip_height = std::max(1U, bitmap.height() >> level);
- const unsigned char *mip_data = bitmap.GetMipData(level, face);
+ const unsigned char *mip_data = bitmap.GetFaceMipData(face, level);
unsigned int mip_size =
Bitmap::GetBufferSize(mip_width, mip_height, bitmap.format());
scoped_array<unsigned char> temp_data;
if (resize_to_pot) {
+ DCHECK(!Texture::IsCompressedFormat(bitmap.format()));
unsigned int pot_width =
std::max(1U, Bitmap::GetPOTSize(bitmap.width()) >> level);
unsigned int pot_height =
@@ -167,7 +169,8 @@ static bool UpdateGLImageFromBitmap(GLenum target,
bitmap.format());
temp_data.reset(new unsigned char[pot_size]);
Bitmap::Scale(mip_width, mip_height, bitmap.format(), mip_data,
- pot_width, pot_height, temp_data.get());
+ pot_width, pot_height, temp_data.get(),
+ Bitmap::GetMipChainSize(pot_width, 1, bitmap.format(), 1));
mip_width = pot_width;
mip_height = pot_height;
mip_size = pot_size;
@@ -218,7 +221,7 @@ static bool CreateGLImagesAndUpload(GLenum target,
for (unsigned int i = 0; i < bitmap.num_mipmaps(); ++i) {
// Upload pixels directly if we can, otherwise it will be done with
// UpdateGLImageFromBitmap afterwards.
- unsigned char *data = resize_to_pot ? NULL : bitmap.GetMipData(i, face);
+ unsigned char *data = resize_to_pot ? NULL : bitmap.GetFaceMipData(face, i);
if (format) {
glTexImage2D(target, i, internal_format, mip_width, mip_height,
@@ -376,9 +379,96 @@ Texture2DGL::~Texture2DGL() {
CHECK_GL_ERROR();
}
+void Texture2DGL::SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect on non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_->image_data());
+ DCHECK(!compressed);
+ // We need to update the backing mipmap and then use that to update the
+ // texture.
+ backing_bitmap_->SetRect(
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format,
+ &gl_data_type);
+ if (gl_format) {
+ if (src_pitch == Bitmap::GetMipChainSize(src_width, 1, format(), 1)) {
+ glTexSubImage2D(GL_TEXTURE_2D, level,
+ dst_left, dst_top,
+ src_width, src_height,
+ gl_format,
+ gl_data_type,
+ src_data);
+ } else {
+ for (int yy = 0; yy < src_height; ++yy) {
+ glTexSubImage2D(GL_TEXTURE_2D, level,
+ dst_left, dst_top + yy,
+ src_width, 1,
+ gl_format,
+ gl_data_type,
+ src_data);
+ src_data = AddPointerOffset<const void*>(src_data, src_pitch);
+ }
+ }
+ } else {
+ glCompressedTexSubImage2D(
+ GL_TEXTURE_2D, level, 0, 0, src_width, src_height,
+ gl_internal_format,
+ Bitmap::GetMipChainSize(src_width, src_height, format(), 1),
+ src_data);
+ }
+ }
+}
+
// Locks the given mipmap level of this texture for loading from main memory,
// and returns a pointer to the buffer.
-bool Texture2DGL::Lock(int level, void** data) {
+bool Texture2DGL::Lock(int level, void** data, int* pitch) {
+ DCHECK(data);
+ DCHECK(pitch);
DLOG(INFO) << "Texture2DGL Lock";
renderer_->MakeCurrentLazy();
if (level >= levels() || level < 0) {
@@ -397,7 +487,18 @@ bool Texture2DGL::Lock(int level, void** data) {
DCHECK_EQ(has_levels_, 0u);
backing_bitmap_->Allocate(format(), width(), height(), levels(), false);
}
- *data = backing_bitmap_->GetMipData(level, TextureCUBE::FACE_POSITIVE_X);
+ *data = backing_bitmap_->GetMipData(level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+ if (IsCompressed()) {
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
if (!HasLevel(level)) {
// TODO: add some API so we don't have to copy back the data if we
// will rewrite it all.
@@ -651,9 +752,104 @@ RenderSurface::Ref TextureCUBEGL::GetRenderSurface(TextureCUBE::CubeFace face,
return render_surface;
}
+void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (static_cast<int>(face) < 0 || static_cast<int>(face) >= NUMBER_OF_FACES) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect invalid face " << face << " on Texture \""
+ << name() << "\"";
+ return;
+ }
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(
+ level, edge_length(), edge_length(), &mip_width, &mip_height);
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_->image_data());
+ DCHECK(!compressed);
+ // We need to update the backing mipmap and then use that to update the
+ // texture.
+ backing_bitmap_->SetFaceRect(face,
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level, face);
+ } else {
+ // TODO(gman): Should this bind be using a FACE id?
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format,
+ &gl_data_type);
+ int gl_face = kCubemapFaceList[face];
+ if (gl_format) {
+ if (src_pitch == Bitmap::GetMipChainSize(src_width, 1, format(), 1)) {
+ glTexSubImage2D(gl_face, level,
+ dst_left, dst_top,
+ src_width, src_height,
+ gl_format,
+ gl_data_type,
+ src_data);
+ } else {
+ for (int yy = 0; yy < src_height; ++yy) {
+ glTexSubImage2D(gl_face, level,
+ dst_left, dst_top + yy,
+ src_width, 1,
+ gl_format,
+ gl_data_type,
+ src_data);
+ src_data = AddPointerOffset<const void*>(src_data, src_pitch);
+ }
+ }
+ } else {
+ glCompressedTexSubImage2D(
+ GL_TEXTURE_2D, level, 0, 0, src_width, src_height,
+ gl_internal_format,
+ Bitmap::GetMipChainSize(src_width, src_height, format(), 1),
+ src_data);
+ }
+ }
+}
+
// Locks the given face and mipmap level of this texture for loading from
// main memory, and returns a pointer to the buffer.
-bool TextureCUBEGL::Lock(CubeFace face, int level, void** data) {
+bool TextureCUBEGL::Lock(CubeFace face, int level, void** data, int* pitch) {
DLOG(INFO) << "TextureCUBEGL Lock";
renderer_->MakeCurrentLazy();
if (level >= levels() || level < 0) {
@@ -676,7 +872,19 @@ bool TextureCUBEGL::Lock(CubeFace face, int level, void** data) {
backing_bitmap_->Allocate(format(), edge_length(), edge_length(),
levels(), true);
}
- *data = backing_bitmap_->GetMipData(level, face);
+ *data = backing_bitmap_->GetFaceMipData(face, level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, edge_length(), edge_length(),
+ &mip_width, &mip_height);
+ if (IsCompressed()) {
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
GLenum gl_target = kCubemapFaceList[face];
if (!HasLevel(level, face)) {
// TODO: add some API so we don't have to copy back the data if we
diff --git a/o3d/core/cross/gl/texture_gl.h b/o3d/core/cross/gl/texture_gl.h
index a647d47..14d0be7 100644
--- a/o3d/core/cross/gl/texture_gl.h
+++ b/o3d/core/cross/gl/texture_gl.h
@@ -68,6 +68,15 @@ class Texture2DGL : public Texture2D {
virtual ~Texture2DGL();
+ // Overridden from Texture2D
+ virtual void SetRect(int level,
+ unsigned left,
+ unsigned top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
+
// Creates a new Texture2DGL with the given specs. If the GL texture
// creation fails then it returns NULL otherwise it returns a pointer to the
// newly created Texture object.
@@ -76,13 +85,6 @@ class Texture2DGL : public Texture2D {
Bitmap *bitmap,
bool enable_render_surfaces);
- // Locks the image buffer of a given mipmap level for writing from main
- // memory.
- virtual bool Lock(int level, void** texture_data);
-
- // Unlocks this texture and returns it to OpenGL control.
- virtual bool Unlock(int level);
-
// Returns the implementation-specific texture handle for this texture.
void* GetTextureHandle() const {
return reinterpret_cast<void*>(gl_texture_);
@@ -103,6 +105,13 @@ class Texture2DGL : public Texture2D {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from Texture2D
+ virtual bool Lock(int level, void** texture_data, int* pitch);
+
+ // Overridden from Texture2D
+ virtual bool Unlock(int level);
+
private:
// Initializes the Texture2DGL from a preexisting OpenGL texture handle
// and raw Bitmap data.
@@ -151,12 +160,15 @@ class TextureCUBEGL : public TextureCUBE {
Bitmap *bitmap,
bool enable_render_surfaces);
- // Locks the image buffer of a given face and mipmap level for loading
- // from main memory.
- virtual bool Lock(CubeFace face, int level, void** texture_data);
-
- // Unlocks the image buffer of a given face and mipmap level.
- virtual bool Unlock(CubeFace face, int level);
+ // Overridden from TextureCUBE
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
// Returns the implementation-specific texture handle for this texture.
virtual void* GetTextureHandle() const {
@@ -182,6 +194,13 @@ class TextureCUBEGL : public TextureCUBE {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from TextureCUBE
+ virtual bool Lock(CubeFace face, int level, void** texture_data, int* pitch);
+
+ // Overridden from TextureCUBE
+ virtual bool Unlock(CubeFace face, int level);
+
private:
// Creates a texture from a pre-existing GL texture object.
TextureCUBEGL(ServiceLocator* service_locator,