summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-01 02:59:36 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-01 02:59:36 +0000
commit38570a4a25452eaa63d0556456f80d33c0e231df (patch)
treede13ded36a0a39340587de17ea8c3a3f712d8080
parent240c058e978c761a1c2ab644e01b8d383988f2b3 (diff)
downloadchromium_src-38570a4a25452eaa63d0556456f80d33c0e231df.zip
chromium_src-38570a4a25452eaa63d0556456f80d33c0e231df.tar.gz
chromium_src-38570a4a25452eaa63d0556456f80d33c0e231df.tar.bz2
Update Texture::Lock to take an AccessMode.
Also, split Lock/Unlock into common and platform specific parts. This is needed to work around an apparent bug in mac drivers where glGetTexImage apparently doesn't always work. This doesn't solve the issue unless we disallow READ completely. Not sure what to about that except make a small GL sample and report the bug to Apple. Review URL: http://codereview.chromium.org/173640 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25012 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--o3d/converter/cross/texture_stub.h22
-rw-r--r--o3d/core/cross/canvas.cc2
-rw-r--r--o3d/core/cross/command_buffer/texture_cb.cc100
-rw-r--r--o3d/core/cross/command_buffer/texture_cb.h22
-rw-r--r--o3d/core/cross/gl/texture_gl.cc107
-rw-r--r--o3d/core/cross/gl/texture_gl.h21
-rw-r--r--o3d/core/cross/pack.cc28
-rw-r--r--o3d/core/cross/texture.cc199
-rw-r--r--o3d/core/cross/texture.h65
-rw-r--r--o3d/core/cross/texture_base.h11
-rw-r--r--o3d/core/cross/texture_test.cc4
-rw-r--r--o3d/core/win/d3d9/texture_d3d9.cc119
-rw-r--r--o3d/core/win/d3d9/texture_d3d9.h11
-rw-r--r--o3d/plugin/cross/texture_static_glue.cc10
14 files changed, 395 insertions, 326 deletions
diff --git a/o3d/converter/cross/texture_stub.h b/o3d/converter/cross/texture_stub.h
index 3a6c74a..5cb17d7 100644
--- a/o3d/converter/cross/texture_stub.h
+++ b/o3d/converter/cross/texture_stub.h
@@ -80,14 +80,14 @@ class Texture2DStub : public Texture2D {
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
protected:
- // Locks the image buffer of a given mipmap level for writing from main
- // memory.
- virtual bool Lock(int level, void** texture_data, int* pitch) {
+ // Overridden from Texture2D
+ virtual bool PlatformSpecificLock(
+ int level, void** texture_data, int* pitch, AccessMode mode) {
return false;
}
- // Unlocks this texture and returns it to Stub control.
- virtual bool Unlock(int level) { return true; }
+ // Overridden from Texture2D
+ virtual bool PlatformSpecificUnlock(int level) { return true; }
// Overridden from Texture2D
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(int mip_level) {
@@ -136,15 +136,15 @@ class TextureCUBEStub : public TextureCUBE {
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
protected:
- // 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, int* pitch) {
+ // Overridden from TextureCUBE
+ virtual bool PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode) {
return false;
}
- // Unlocks the image buffer of a given face and mipmap level.
- virtual bool Unlock(CubeFace face, int level) { return true; }
+ // Overridden from TextureCUBE
+ virtual bool PlatformSpecificUnlock(CubeFace face, int level) { return true; }
// Overridden from TextureCUBE
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(CubeFace face,
diff --git a/o3d/core/cross/canvas.cc b/o3d/core/cross/canvas.cc
index 0484e33..a2aa30d 100644
--- a/o3d/core/cross/canvas.cc
+++ b/o3d/core/cross/canvas.cc
@@ -161,7 +161,7 @@ void Canvas::DrawBitmap(Texture2D* texture2d,
return;
}
- Texture2D::LockHelper lock_helper(texture2d, 0);
+ Texture2D::LockHelper lock_helper(texture2d, 0, Texture::kWriteOnly);
uint8* texture_data = lock_helper.GetDataAs<uint8>();
if (!texture_data) {
return;
diff --git a/o3d/core/cross/command_buffer/texture_cb.cc b/o3d/core/cross/command_buffer/texture_cb.cc
index e01e1ce..aac3649 100644
--- a/o3d/core/cross/command_buffer/texture_cb.cc
+++ b/o3d/core/cross/command_buffer/texture_cb.cc
@@ -257,8 +257,9 @@ Texture2DCB::Texture2DCB(ServiceLocator* service_locator,
renderer_(static_cast<RendererCB*>(
service_locator->GetService<Renderer>())),
resource_id_(resource_id),
+ backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))),
has_levels_(0),
- backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))) {
+ locked_levels_(0) {
DCHECK_NE(format, Texture::UNKNOWN_FORMAT);
}
@@ -377,19 +378,10 @@ void Texture2DCB::SetRect(int level,
// Locks the given mipmap level of this texture for loading from main memory,
// and returns a pointer to the buffer.
-bool Texture2DCB::Lock(int level, void** data, int* pitch) {
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to lock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (IsLocked(level)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is already locked.";
- return false;
- }
+bool Texture2DCB::PlatformSpecificLock(
+ int level, void** data, int* pitch, AccessMode mode) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
if (!backing_bitmap_->image_data()) {
DCHECK_EQ(has_levels_, 0);
backing_bitmap_->Allocate(format(), width(), height(), levels(),
@@ -406,7 +398,7 @@ bool Texture2DCB::Lock(int level, void** data, int* pitch) {
unsigned bytes_per_row = bytes_per_block * blocks_across;
*pitch = bytes_per_row;
}
- if (!HasLevel(level)) {
+ if (mode != kWriteOnly && !HasLevel(level)) {
DCHECK_EQ(backing_bitmap_->width(), width());
DCHECK_EQ(backing_bitmap_->height(), height());
DCHECK_EQ(backing_bitmap_->format(), format());
@@ -422,28 +414,20 @@ bool Texture2DCB::Lock(int level, void** data, int* pitch) {
// Unlocks the given mipmap level of this texture, uploading the main memory
// data buffer to the command buffer service.
-bool Texture2DCB::Unlock(int level) {
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to unlock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (!IsLocked(level)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is not locked.";
- return false;
- }
+bool Texture2DCB::PlatformSpecificUnlock(int level) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
DCHECK(backing_bitmap_->image_data());
DCHECK_EQ(backing_bitmap_->width(), width());
DCHECK_EQ(backing_bitmap_->height(), height());
DCHECK_EQ(backing_bitmap_->format(), format());
DCHECK_GT(backing_bitmap_->num_mipmaps(), level);
- DCHECK(HasLevel(level));
- UpdateResourceFromBitmap(renderer_, resource_id_, level,
- TextureCUBE::FACE_POSITIVE_X,
- *backing_bitmap_.Get());
+ if (LockedMode(level) != kReadOnly) {
+ DCHECK(HasLevel(level));
+ UpdateResourceFromBitmap(renderer_, resource_id_, level,
+ TextureCUBE::FACE_POSITIVE_X,
+ *backing_bitmap_.Get());
+ }
locked_levels_ &= ~(1 << level);
if (locked_levels_ == 0) {
backing_bitmap_->FreeData();
@@ -500,6 +484,7 @@ TextureCUBECB::TextureCUBECB(ServiceLocator* service_locator,
for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) {
backing_bitmaps_[ii] = Bitmap::Ref(new Bitmap(service_locator));
has_levels_[ii] = 0;
+ locked_levels_[ii] = 0;
}
}
@@ -623,20 +608,13 @@ void TextureCUBECB::SetRect(TextureCUBE::CubeFace face,
// Locks the given face and mipmap level of this texture for loading from
// main memory, and returns a pointer to the buffer.
-bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) {
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to lock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (IsLocked(level, face)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " Face " << face
- << " of texture \"" << name()
- << "\" is already locked.";
- return false;
- }
+bool TextureCUBECB::PlatformSpecificLock(
+ CubeFace face, int level, void** data, int* pitch,
+ Texture::AccessMode mode) {
+ DCHECK(data);
+ DCHECK(pitch);
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
if (!backing_bitmap->image_data()) {
DCHECK_EQ(has_levels_[face], 0);
@@ -653,9 +631,7 @@ bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) {
unsigned bytes_per_row = bytes_per_block * blocks_across;
*pitch = bytes_per_row;
}
- if (!HasLevel(level, face)) {
- // TODO: add some API so we don't have to copy back the data if we
- // will rewrite it all.
+ if (mode != kWriteOnly && !HasLevel(face, level)) {
DCHECK_EQ(backing_bitmap->width(), edge_length());
DCHECK_EQ(backing_bitmap->height(), edge_length());
DCHECK_EQ(backing_bitmap->format(), format());
@@ -669,29 +645,21 @@ bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) {
}
// Unlocks the given face and mipmap level of this texture.
-bool TextureCUBECB::Unlock(CubeFace face, int level) {
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to unlock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (!IsLocked(level, face)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " Face " << face
- << " of texture \"" << name()
- << "\" is not locked.";
- return false;
- }
+bool TextureCUBECB::PlatformSpecificUnlock(CubeFace face, int level) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
DCHECK(backing_bitmap->image_data());
DCHECK_EQ(backing_bitmap->width(), edge_length());
DCHECK_EQ(backing_bitmap->height(), edge_length());
DCHECK_EQ(backing_bitmap->format(), format());
DCHECK_GT(backing_bitmap->num_mipmaps(), level);
- DCHECK(HasLevel(level, face));
- UpdateResourceFromBitmap(renderer_, resource_id_, level, face,
- *backing_bitmap);
+
+ if (LockedMode(face, level) != kReadOnly) {
+ DCHECK(HasLevel(face, level));
+ UpdateResourceFromBitmap(renderer_, resource_id_, level, face,
+ *backing_bitmap);
+ }
locked_levels_[face] &= ~(1 << level);
if (locked_levels_[face] == 0) {
backing_bitmap->FreeData();
diff --git a/o3d/core/cross/command_buffer/texture_cb.h b/o3d/core/cross/command_buffer/texture_cb.h
index 3f1b812..e0e85d2 100644
--- a/o3d/core/cross/command_buffer/texture_cb.h
+++ b/o3d/core/cross/command_buffer/texture_cb.h
@@ -89,10 +89,11 @@ class Texture2DCB : public Texture2D {
protected:
// Overridden from Texture2D
- virtual bool Lock(int level, void** texture_data, int* pitch);
+ virtual bool PlatformSpecificLock(
+ int level, void** texture_data, int* pitch, AccessMode mode);
// Overridden from Texture2D
- virtual bool Unlock(int level);
+ virtual bool PlatformSpecificUnlock(int level);
// Overridden from Texture2D
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(int mip_level);
@@ -125,6 +126,9 @@ class Texture2DCB : public Texture2D {
// Bitfield that indicates mip levels that are currently stored in the
// backing bitmap.
unsigned int has_levels_;
+
+ // Bitfield that indicates which mip levels are currently locked.
+ unsigned int locked_levels_;
};
// TextureCUBECB ---------------------------------------------------------------
@@ -166,11 +170,12 @@ class TextureCUBECB : public TextureCUBE {
protected:
// Overridden from TextureCUBE
- virtual bool Lock(
- CubeFace face, int level, void** texture_data, int* pitch);
+ virtual bool PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode);
// Overridden from TextureCUBE
- virtual bool Unlock(CubeFace face, int level);
+ virtual bool PlatformSpecificUnlock(CubeFace face, int level);
// Overridden from TextureCUBE.
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(CubeFace face,
@@ -186,7 +191,7 @@ class TextureCUBECB : public TextureCUBE {
// Returns true if the backing bitmap has the data for the level.
- bool HasLevel(unsigned int level, CubeFace face) {
+ bool HasLevel(CubeFace face, unsigned int level) {
DCHECK_LT(level, levels());
return (has_levels_[face] & (1 << level)) != 0;
}
@@ -199,7 +204,10 @@ class TextureCUBECB : public TextureCUBE {
// Bitfields that indicates mip levels that are currently stored in the
// backing bitmap, one per face.
- unsigned int has_levels_[6];
+ unsigned int has_levels_[NUMBER_OF_FACES];
+
+ // Bitfields that indicates which levels are currently locked, one per face.
+ unsigned int locked_levels_[NUMBER_OF_FACES];
};
} // namespace o3d
diff --git a/o3d/core/cross/gl/texture_gl.cc b/o3d/core/cross/gl/texture_gl.cc
index 4438025..a424e0a 100644
--- a/o3d/core/cross/gl/texture_gl.cc
+++ b/o3d/core/cross/gl/texture_gl.cc
@@ -262,7 +262,8 @@ Texture2DGL::Texture2DGL(ServiceLocator* service_locator,
service_locator->GetService<Renderer>())),
gl_texture_(texture),
backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))),
- has_levels_(0) {
+ has_levels_(0),
+ locked_levels_(0) {
DLOG(INFO) << "Texture2DGL Construct from GLint";
DCHECK_NE(format, Texture::UNKNOWN_FORMAT);
}
@@ -451,23 +452,14 @@ void Texture2DGL::SetRect(int level,
// 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, int* pitch) {
+bool Texture2DGL::PlatformSpecificLock(
+ int level, void** data, int* pitch, Texture::AccessMode mode) {
+ DLOG(INFO) << "Texture2DGL Lock";
DCHECK(data);
DCHECK(pitch);
- DLOG(INFO) << "Texture2DGL Lock";
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
renderer_->MakeCurrentLazy();
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to lock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (IsLocked(level)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is already locked.";
- return false;
- }
if (!backing_bitmap_->image_data()) {
DCHECK_EQ(has_levels_, 0u);
backing_bitmap_->Allocate(format(), width(), height(), levels(),
@@ -483,9 +475,7 @@ bool Texture2DGL::Lock(int level, void** data, int* pitch) {
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.
+ if (mode != kWriteOnly && !HasLevel(level)) {
DCHECK(!resize_to_pot_);
GLenum gl_internal_format = 0;
GLenum gl_data_type = 0;
@@ -503,22 +493,15 @@ bool Texture2DGL::Lock(int level, void** data, int* pitch) {
// Unlocks the given mipmap level of this texture, uploading the main memory
// data buffer to GL.
-bool Texture2DGL::Unlock(int level) {
+bool Texture2DGL::PlatformSpecificUnlock(int level) {
DLOG(INFO) << "Texture2DGL Unlock";
- renderer_->MakeCurrentLazy();
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to unlock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (!IsLocked(level)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is not locked.";
- return false;
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+ if (LockedMode(level) != kReadOnly) {
+ DCHECK(HasLevel(level));
+ renderer_->MakeCurrentLazy();
+ UpdateBackedMipLevel(level);
}
- UpdateBackedMipLevel(level);
locked_levels_ &= ~(1 << level);
if (!resize_to_pot_ && (locked_levels_ == 0)) {
backing_bitmap_->FreeData();
@@ -581,6 +564,7 @@ TextureCUBEGL::TextureCUBEGL(ServiceLocator* service_locator,
for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) {
backing_bitmaps_[ii] = Bitmap::Ref(new Bitmap(service_locator));
has_levels_[ii] = 0;
+ locked_levels_[ii] = 0;
}
}
@@ -681,7 +665,7 @@ void TextureCUBEGL::UpdateBackedMipLevel(unsigned int level,
DCHECK_EQ(backing_bitmap->width(), static_cast<unsigned int>(edge_length()));
DCHECK_EQ(backing_bitmap->height(), static_cast<unsigned int>(edge_length()));
DCHECK_EQ(backing_bitmap->format(), format());
- DCHECK(HasLevel(level, face));
+ DCHECK(HasLevel(face, level));
renderer_->MakeCurrentLazy();
glBindTexture(GL_TEXTURE_2D, gl_texture_);
UpdateGLImageFromBitmap(kCubemapFaceList[face], level, face,
@@ -808,25 +792,16 @@ void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face,
// 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, int* pitch) {
+bool TextureCUBEGL::PlatformSpecificLock(
+ CubeFace face, int level, void** data, int* pitch,
+ Texture::AccessMode mode) {
DLOG(INFO) << "TextureCUBEGL Lock";
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
renderer_->MakeCurrentLazy();
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to lock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (IsLocked(level, face)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " Face " << face
- << " of texture \"" << name()
- << "\" is already locked.";
- return false;
- }
Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
if (!backing_bitmap->image_data()) {
- for (unsigned int i = 0; i < 6; ++i) {
+ for (int i = 0; i < static_cast<int>(NUMBER_OF_FACES); ++i) {
DCHECK_EQ(has_levels_[i], 0u);
}
backing_bitmap->Allocate(format(), edge_length(), edge_length(), levels(),
@@ -843,7 +818,7 @@ bool TextureCUBEGL::Lock(CubeFace face, int level, void** data, int* pitch) {
*pitch = bytes_per_row;
}
GLenum gl_target = kCubemapFaceList[face];
- if (!HasLevel(level, face)) {
+ if (mode != kWriteOnly && !HasLevel(face, level)) {
// TODO: add some API so we don't have to copy back the data if we
// will rewrite it all.
DCHECK(!resize_to_pot_);
@@ -856,34 +831,30 @@ bool TextureCUBEGL::Lock(CubeFace face, int level, void** data, int* pitch) {
glGetTexImage(gl_target, level, gl_format, gl_data_type, *data);
has_levels_[face] |= 1 << level;
}
- locked_levels_[face] |= 1 << level;
CHECK_GL_ERROR();
+
+ locked_levels_[face] |= 1 << level;
+
return false;
}
// Unlocks the given face and mipmap level of this texture.
-bool TextureCUBEGL::Unlock(CubeFace face, int level) {
+bool TextureCUBEGL::PlatformSpecificUnlock(CubeFace face, int level) {
DLOG(INFO) << "TextureCUBEGL Unlock";
- renderer_->MakeCurrentLazy();
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to unlock inexistent level " << level
- << " on Texture \"" << name();
- return false;
- }
- if (!IsLocked(level, face)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " Face " << face
- << " of texture \"" << name()
- << "\" is not locked.";
- return false;
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+ if (LockedMode(face, level) != kReadOnly) {
+ DCHECK(HasLevel(face, level));
+ renderer_->MakeCurrentLazy();
+ UpdateBackedMipLevel(level, face);
}
- UpdateBackedMipLevel(level, face);
- Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
locked_levels_[face] &= ~(1 << level);
+
if (!resize_to_pot_) {
+ // See if we can throw away the backing bitmap.
+ Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
bool has_locked_level = false;
- for (unsigned int i = 0; i < 6; ++i) {
+ for (int i = 0; i < static_cast<int>(NUMBER_OF_FACES); ++i) {
if (locked_levels_[i]) {
has_locked_level = true;
break;
@@ -891,7 +862,7 @@ bool TextureCUBEGL::Unlock(CubeFace face, int level) {
}
if (!has_locked_level) {
backing_bitmap->FreeData();
- for (unsigned int i = 0; i < 6; ++i) {
+ for (int i = 0; i < static_cast<int>(NUMBER_OF_FACES); ++i) {
has_levels_[i] = 0;
}
}
diff --git a/o3d/core/cross/gl/texture_gl.h b/o3d/core/cross/gl/texture_gl.h
index be1fcbd..3a74b85 100644
--- a/o3d/core/cross/gl/texture_gl.h
+++ b/o3d/core/cross/gl/texture_gl.h
@@ -101,10 +101,11 @@ class Texture2DGL : public Texture2D {
protected:
// Overridden from Texture2D
- virtual bool Lock(int level, void** texture_data, int* pitch);
+ virtual bool PlatformSpecificLock(
+ int level, void** texture_data, int* pitch, AccessMode mode);
// Overridden from Texture2D
- virtual bool Unlock(int level);
+ virtual bool PlatformSpecificUnlock(int level);
// Overridden from Texture2D
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(int mip_level);
@@ -148,6 +149,9 @@ class Texture2DGL : public Texture2D {
// Bitfield that indicates mip levels that are currently stored in the
// backing bitmap.
unsigned int has_levels_;
+
+ // Bitfield that indicates which levels are currently locked.
+ unsigned int locked_levels_;
};
@@ -190,10 +194,12 @@ class TextureCUBEGL : public TextureCUBE {
protected:
// Overridden from TextureCUBE
- virtual bool Lock(CubeFace face, int level, void** texture_data, int* pitch);
+ virtual bool PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode);
// Overridden from TextureCUBE
- virtual bool Unlock(CubeFace face, int level);
+ virtual bool PlatformSpecificUnlock(CubeFace face, int level);
// Overridden from TextureCUBE.
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(CubeFace face,
@@ -213,7 +219,7 @@ class TextureCUBEGL : public TextureCUBE {
void UpdateBackedMipLevel(unsigned int level, CubeFace face);
// Returns true if the backing bitmap has the data for the level.
- bool HasLevel(unsigned int level, CubeFace face) const {
+ bool HasLevel(CubeFace face, unsigned int level) const {
DCHECK_LT(static_cast<int>(level), levels());
return (has_levels_[face] & (1 << level)) != 0;
}
@@ -232,7 +238,10 @@ class TextureCUBEGL : public TextureCUBE {
// Bitfields that indicates mip levels that are currently stored in the
// backing bitmap, one per face.
- unsigned int has_levels_[6];
+ unsigned int has_levels_[NUMBER_OF_FACES];
+
+ // Bitfields that indicates which levels are currently locked, one per face.
+ unsigned int locked_levels_[NUMBER_OF_FACES];
};
} // namespace o3d
diff --git a/o3d/core/cross/pack.cc b/o3d/core/cross/pack.cc
index 5dd6c7e..bcc5c06 100644
--- a/o3d/core/cross/pack.cc
+++ b/o3d/core/cross/pack.cc
@@ -166,14 +166,14 @@ Texture* Pack::CreateTextureFromBitmaps(
for (BitmapRefArray::size_type ii = 0; ii < bitmaps.size(); ++ii) {
temp_bitmaps.push_back(bitmaps[ii]);
Bitmap* bitmap = temp_bitmaps[ii].Get();
- if (bitmap->width() > static_cast<unsigned int>(Texture::MAX_DIMENSION) ||
- bitmap->height() > static_cast<unsigned int>(Texture::MAX_DIMENSION)) {
+ if (bitmap->width() > static_cast<unsigned int>(Texture::kMaxDimension) ||
+ bitmap->height() > static_cast<unsigned int>(Texture::kMaxDimension)) {
O3D_ERROR(service_locator())
<< "Bitmap (uri='" << uri
<< "', size=" << bitmap->width() << "x" << bitmap->height()
<< ", mips=" << bitmap->num_mipmaps()<< ") is larger than the "
- << "maximum texture size which is (" << Texture::MAX_DIMENSION
- << "x" << Texture::MAX_DIMENSION << ")";
+ << "maximum texture size which is (" << Texture::kMaxDimension
+ << "x" << Texture::kMaxDimension << ")";
return NULL;
}
if (bitmap->width() != width || bitmap->height() != height) {
@@ -320,11 +320,11 @@ Texture2D* Pack::CreateTexture2D(int width,
return NULL;
}
- if (width > Texture::MAX_DIMENSION ||
- height > Texture::MAX_DIMENSION) {
+ if (width > Texture::kMaxDimension ||
+ height > Texture::kMaxDimension) {
O3D_ERROR(service_locator())
- << "Maximum texture size is (" << Texture::MAX_DIMENSION << "x"
- << Texture::MAX_DIMENSION << ")";
+ << "Maximum texture size is (" << Texture::kMaxDimension << "x"
+ << Texture::kMaxDimension << ")";
return NULL;
}
@@ -361,9 +361,9 @@ TextureCUBE* Pack::CreateTextureCUBE(int edge_length,
return NULL;
}
- if (edge_length > Texture::MAX_DIMENSION) {
+ if (edge_length > Texture::kMaxDimension) {
O3D_ERROR(service_locator())
- << "Maximum edge_length is " << Texture::MAX_DIMENSION;
+ << "Maximum edge_length is " << Texture::kMaxDimension;
return NULL;
}
@@ -398,11 +398,11 @@ RenderDepthStencilSurface* Pack::CreateDepthStencilSurface(int width,
return NULL;
}
- if (width > Texture::MAX_DIMENSION ||
- height > Texture::MAX_DIMENSION) {
+ if (width > Texture::kMaxDimension ||
+ height > Texture::kMaxDimension) {
O3D_ERROR(service_locator())
- << "Maximum texture size is (" << Texture::MAX_DIMENSION << "x"
- << Texture::MAX_DIMENSION << ")";
+ << "Maximum texture size is (" << Texture::kMaxDimension << "x"
+ << Texture::kMaxDimension << ")";
return NULL;
}
diff --git a/o3d/core/cross/texture.cc b/o3d/core/cross/texture.cc
index bbed3e6..541864b 100644
--- a/o3d/core/cross/texture.cc
+++ b/o3d/core/cross/texture.cc
@@ -59,13 +59,16 @@ Texture2D::Texture2D(ServiceLocator* service_locator,
int levels,
bool enable_render_surfaces)
: Texture(service_locator, format, levels, enable_render_surfaces),
- locked_levels_(0),
surface_map_(levels) {
RegisterReadOnlyParamRef(kWidthParamName, &width_param_);
RegisterReadOnlyParamRef(kHeightParamName, &height_param_);
width_param_->set_read_only_value(width);
height_param_->set_read_only_value(height);
+ for (int ii = 0; ii < kMaxLevels; ++ii) {
+ locked_levels_[ii] = kNone;
+ }
+
ClientInfoManager* client_info_manager =
service_locator->GetService<ClientInfoManager>();
client_info_manager->AdjustTextureMemoryUsed(
@@ -74,10 +77,17 @@ Texture2D::Texture2D(ServiceLocator* service_locator,
}
Texture2D::~Texture2D() {
- if (locked_levels_ != 0) {
- O3D_ERROR(service_locator())
- << "Texture2D \"" << name()
- << "\" was never unlocked before being destroyed.";
+ bool reported = false;
+ for (int ii = 0; ii < levels(); ++ii) {
+ if (IsLocked(ii)) {
+ if (!reported) {
+ reported = true;
+ O3D_ERROR(service_locator())
+ << "Texture2D \"" << name()
+ << "\" was never unlocked before being destroyed.";
+ }
+ Unlock(ii);
+ }
}
ClientInfoManager* client_info_manager =
@@ -163,7 +173,7 @@ void Texture2D::DrawImage(const Bitmap& src_img,
return;
}
- LockHelper helper(this, dst_mip);
+ LockHelper helper(this, dst_mip, kWriteOnly);
uint8* mip_data = helper.GetDataAs<uint8>();
if (!mip_data) {
return;
@@ -230,7 +240,7 @@ void Texture2D::DrawImage(const Canvas& src_img,
return;
}
- LockHelper helper(this, dst_mip);
+ LockHelper helper(this, dst_mip, kWriteOnly);
uint8* mip_data = helper.GetDataAs<uint8>();
if (!mip_data) {
return;
@@ -279,8 +289,8 @@ void Texture2D::GenerateMips(int source_level, int num_levels) {
for (int ii = 0; ii < num_levels; ++ii) {
int level = source_level + ii;
- Texture2D::LockHelper src_helper(this, level);
- Texture2D::LockHelper dst_helper(this, level + 1);
+ Texture2D::LockHelper src_helper(this, level, kReadOnly);
+ Texture2D::LockHelper dst_helper(this, level + 1, kWriteOnly);
const uint8* src_data = src_helper.GetDataAs<const uint8>();
if (!src_data) {
O3D_ERROR(service_locator())
@@ -302,6 +312,59 @@ void Texture2D::GenerateMips(int source_level, int num_levels) {
}
}
+bool Texture2D::Lock(
+ int level, void** texture_data, int* pitch, AccessMode mode) {
+ DCHECK(texture_data);
+ DCHECK(pitch);
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to lock inexistent level " << level << " on Texture \""
+ << name() << "\"";
+ return false;
+ }
+ if (IsLocked(level)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " of texture \"" << name()
+ << "\" is already locked.";
+ return false;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to lock a render-target texture: " << name();
+ return false;
+ }
+ bool success = PlatformSpecificLock(level, texture_data, pitch, mode);
+ if (success) {
+ locked_levels_[level] = mode;
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Lock Texture2D";
+ }
+ return success;
+}
+
+// Unlocks the given mipmap level of this texture.
+bool Texture2D::Unlock(int level) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to unlock inexistent level " << level << " on Texture \""
+ << name() << "\"";
+ return false;
+ }
+ if (!IsLocked(level)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " of texture \"" << name()
+ << "\" is not locked.";
+ return false;
+ }
+ bool result = PlatformSpecificUnlock(level);
+ if (result) {
+ locked_levels_[level] = kNone;
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Unlock Texture2D";
+ }
+ return result;
+}
+
ObjectBase::Ref Texture2D::Create(ServiceLocator* service_locator) {
return ObjectBase::Ref();
}
@@ -318,8 +381,10 @@ RenderSurface::Ref Texture2D::GetRenderSurface(int mip_level) {
return surface_map_[mip_level];
}
-Texture2D::LockHelper::LockHelper(Texture2D* texture, int level)
- : texture_(texture),
+Texture2D::LockHelper::LockHelper(
+ Texture2D* texture, int level, Texture::AccessMode mode)
+ : mode_(mode),
+ texture_(texture),
level_(level),
data_(NULL),
locked_(false) {
@@ -333,7 +398,7 @@ Texture2D::LockHelper::~LockHelper() {
void* Texture2D::LockHelper::GetData() {
if (!locked_) {
- locked_ = texture_->Lock(level_, &data_, &pitch_);
+ locked_ = texture_->Lock(level_, &data_, &pitch_, mode_);
if (!locked_) {
O3D_ERROR(texture_->service_locator())
<< "Unable to lock buffer '" << texture_->name() << "'";
@@ -348,9 +413,11 @@ TextureCUBE::TextureCUBE(ServiceLocator* service_locator,
int levels,
bool enable_render_surfaces)
: Texture(service_locator, format, levels, enable_render_surfaces) {
- for (unsigned int i = 0; i < 6; ++i) {
- locked_levels_[i] = 0;
- surface_maps_[i].resize(levels);
+ for (int f = 0; f < static_cast<int>(NUMBER_OF_FACES); ++f) {
+ for (int ii = 0; ii < kMaxLevels; ++ii) {
+ locked_levels_[f][ii] = kNone;
+ }
+ surface_maps_[f].resize(levels);
}
RegisterReadOnlyParamRef(kEdgeLengthParamName, &edge_length_param_);
edge_length_param_->set_read_only_value(edge_length);
@@ -358,19 +425,27 @@ TextureCUBE::TextureCUBE(ServiceLocator* service_locator,
ClientInfoManager* client_info_manager =
service_locator->GetService<ClientInfoManager>();
client_info_manager->AdjustTextureMemoryUsed(
- static_cast<int>(image::ComputeMipChainSize(edge_length,
- edge_length,
- format,
- levels)) * 6);
+ static_cast<int>(image::ComputeMipChainSize(
+ edge_length,
+ edge_length,
+ format,
+ levels)) * static_cast<int>(NUMBER_OF_FACES));
}
TextureCUBE::~TextureCUBE() {
- for (unsigned int i = 0; i < 6; ++i) {
- if (locked_levels_[i] != 0) {
- O3D_ERROR(service_locator())
- << "TextureCUBE \"" << name() << "\" was never unlocked before"
- << "being destroyed.";
- break; // No need to report it more than once.
+ bool reported = false;
+ for (int f = 0; f < static_cast<int>(NUMBER_OF_FACES); ++f) {
+ for (int i = 0; i < levels(); ++i) {
+ if (IsLocked(static_cast<CubeFace>(f), i)) {
+ if (!reported) {
+ // No need to report it more than once.
+ reported = true;
+ O3D_ERROR(service_locator())
+ << "TextureCUBE \"" << name() << "\" was never unlocked before"
+ << "being destroyed.";
+ }
+ Unlock(static_cast<CubeFace>(f), i);
+ }
}
}
@@ -476,7 +551,7 @@ void TextureCUBE::DrawImage(const Bitmap& src_img, int src_mip,
src_pitch);
}
- LockHelper helper(this, dest_face, dest_mip);
+ LockHelper helper(this, dest_face, dest_mip, kWriteOnly);
uint8* mip_data = helper.GetDataAs<uint8>();
if (!mip_data) {
return;
@@ -544,7 +619,7 @@ void TextureCUBE::DrawImage(const Canvas& src_img,
return;
}
- LockHelper helper(this, dest_face, dest_mip);
+ LockHelper helper(this, dest_face, dest_mip, kWriteOnly);
uint8* mip_data = helper.GetDataAs<uint8>();
if (!mip_data) {
return;
@@ -595,9 +670,10 @@ void TextureCUBE::GenerateMips(int source_level, int num_levels) {
for (int ii = 0; ii < num_levels; ++ii) {
int level = source_level + ii;
TextureCUBE::LockHelper src_helper(
- this, static_cast<TextureCUBE::CubeFace>(face), level);
+ this, static_cast<TextureCUBE::CubeFace>(face), level, kReadOnly);
TextureCUBE::LockHelper dst_helper(
- this, static_cast<TextureCUBE::CubeFace>(face), level + 1);
+ this, static_cast<TextureCUBE::CubeFace>(face), level + 1,
+ kWriteOnly);
const uint8* src_data = src_helper.GetDataAs<const uint8>();
if (!src_data) {
O3D_ERROR(service_locator())
@@ -622,11 +698,70 @@ void TextureCUBE::GenerateMips(int source_level, int num_levels) {
}
}
+// Locks the given face and mipmap level of this texture for loading from
+// main memory, and returns a pointer to the buffer.
+bool TextureCUBE::Lock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode) {
+ DCHECK(texture_data);
+ DCHECK(pitch);
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to lock inexistent level " << level << " on Texture \""
+ << name();
+ return false;
+ }
+ if (IsLocked(face, level)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " Face " << face << " of texture \"" << name()
+ << "\" is already locked.";
+ return false;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to lock a render-target texture: " << name();
+ return false;
+ }
+
+ bool success = PlatformSpecificLock(face, level, texture_data, pitch, mode);
+ if (success) {
+ locked_levels_[face][level] = mode;
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Lock TextureCUBE";
+ }
+ return success;
+}
+
+// Unlocks the given face and mipmap level of this texture.
+bool TextureCUBE::Unlock(CubeFace face, int level) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to unlock inexistent level " << level << " on Texture \""
+ << name();
+ return false;
+ }
+ if (!IsLocked(face, level)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " of texture \"" << name()
+ << "\" is not locked.";
+ return false;
+ }
+ bool result = PlatformSpecificUnlock(face, level);
+ if (result) {
+ locked_levels_[face][level] = kNone;
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Unlock TextureCUBE";
+ }
+ return result;
+}
+
TextureCUBE::LockHelper::LockHelper(
TextureCUBE* texture,
CubeFace face,
- int level)
- : texture_(texture),
+ int level,
+ Texture::AccessMode mode)
+ : mode_(mode),
+ texture_(texture),
face_(face),
level_(level),
data_(NULL),
@@ -641,7 +776,7 @@ TextureCUBE::LockHelper::~LockHelper() {
void* TextureCUBE::LockHelper::GetData() {
if (!locked_) {
- locked_ = texture_->Lock(face_, level_, &data_, &pitch_);
+ locked_ = texture_->Lock(face_, level_, &data_, &pitch_, mode_);
if (!locked_) {
O3D_ERROR(texture_->service_locator())
<< "Unable to lock buffer '" << texture_->name() << "'";
diff --git a/o3d/core/cross/texture.h b/o3d/core/cross/texture.h
index fcaf75a..f25a162 100644
--- a/o3d/core/cross/texture.h
+++ b/o3d/core/cross/texture.h
@@ -54,7 +54,7 @@ class Texture2D : public Texture {
// Class to help lock Texture2D. Automatically unlocks texture in destructor.
class LockHelper {
public:
- explicit LockHelper(Texture2D* texture, int level);
+ explicit LockHelper(Texture2D* texture, int level, AccessMode mode);
~LockHelper();
int pitch() const {
@@ -74,6 +74,7 @@ class Texture2D : public Texture {
}
private:
+ AccessMode mode_;
Texture2D* texture_;
int level_;
int pitch_;
@@ -182,9 +183,10 @@ class Texture2D : public Texture {
// texture_data: [out] a pointer to the current texture data
// pitch: bytes across 1 row of pixels if uncompressed format. bytes across 1
// row of blocks if compressed format.
+ // mode: The access mode.
// Returns:
// true if the operation succeeds
- virtual bool Lock(int level, void** texture_data, int* pitch) = 0;
+ bool Lock(int level, void** texture_data, int* pitch, AccessMode mode);
// Notifies the texture object that the internal texture data has been
// been modified. Unlock must be called in conjunction with Lock. Modifying
@@ -194,20 +196,30 @@ class Texture2D : public Texture {
// level: [in] the mipmap level that was modified
// Returns:
// true if the operation succeeds
- virtual bool Unlock(int level) = 0;
+ bool Unlock(int level);
+
+ // The platform specific part of Lock.
+ virtual bool PlatformSpecificLock(int level, void** texture_data, int* pitch,
+ AccessMode mode) = 0;
+
+ // The platform specific part of Unlock.
+ virtual bool PlatformSpecificUnlock(int level) = 0;
// The platform specific part of GetRenderSurface.
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(
int mip_level) = 0;
+ // Returns the current locked mode.
+ AccessMode LockedMode(unsigned int level) {
+ DCHECK_LT(static_cast<int>(level), levels());
+ return locked_levels_[level];
+ }
+
// Returns true if the mip-map level has been locked.
bool IsLocked(unsigned int level) {
- DCHECK_LT(static_cast<int>(level), levels());
- return (locked_levels_ & (1 << level)) != 0;
+ return LockedMode(level) != kNone;
}
- // Bitfield that indicates mip levels that are currently locked.
- unsigned int locked_levels_;
private:
friend class IClassManager;
@@ -222,6 +234,9 @@ class Texture2D : public Texture {
// The height of the texture, in texels.
ParamInteger::Ref height_param_;
+ // Access mode for each level.
+ AccessMode locked_levels_[kMaxLevels];
+
O3D_DECL_CLASS(Texture2D, Texture);
DISALLOW_COPY_AND_ASSIGN(Texture2D);
};
@@ -244,7 +259,8 @@ class TextureCUBE : public Texture {
// Automatically unlocks texture in destructor.
class LockHelper {
public:
- explicit LockHelper(TextureCUBE* texture, CubeFace face, int level);
+ explicit LockHelper(TextureCUBE* texture, CubeFace face, int level,
+ AccessMode mode);
~LockHelper();
int pitch() const {
@@ -264,6 +280,7 @@ class TextureCUBE : public Texture {
}
private:
+ AccessMode mode_;
TextureCUBE* texture_;
CubeFace face_;
int level_;
@@ -378,10 +395,12 @@ class TextureCUBE : public Texture {
// texture_data: [out] a pointer to the current texture data
// pitch: bytes across 1 row of pixels if uncompressed format. bytes across 1
// row of blocks if compressed format.
+ // mode: The access mode.
// Returns:
// true if the operation succeeds
- virtual bool Lock(
- CubeFace face, int level, void** texture_data, int* pitch) = 0;
+ bool Lock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode);
// Notifies the texture object that the internal texture data has been
// been modified. Unlock must be called in conjunction with Lock.
@@ -392,21 +411,30 @@ class TextureCUBE : public Texture {
// level: [in] the mipmap level that was modified
// Returns:
// true if the operation succeeds
- virtual bool Unlock(CubeFace face, int level) = 0;
+ bool Unlock(CubeFace face, int level);
+
+ // The platform specific part of Lock.
+ virtual bool PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode) = 0;
+
+ // The platform specific part of Unlock.
+ virtual bool PlatformSpecificUnlock(CubeFace face, int level) = 0;
// The platform specific part of GetRenderSurface.
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(
CubeFace face, int level) = 0;
- // Returns true if the mip-map level has been locked.
- bool IsLocked(unsigned int level, CubeFace face) {
+ // Returns the locked mode for a level
+ AccessMode LockedMode(CubeFace face, unsigned int level) {
DCHECK_LT(static_cast<int>(level), levels());
- return (locked_levels_[face] & (1 << level)) != 0;
+ return locked_levels_[face][level];
}
- // Bitfields that indicates mip levels that are currently locked, one per
- // face.
- unsigned int locked_levels_[NUMBER_OF_FACES];
+ // Returns true if the mip-map level has been locked.
+ bool IsLocked(CubeFace face, unsigned int level) {
+ return LockedMode(face, level) != kNone;
+ }
private:
friend class IClassManager;
@@ -419,6 +447,9 @@ class TextureCUBE : public Texture {
// The length of each edge of the cube, in texels.
ParamInteger::Ref edge_length_param_;
+ // AccessMode for each level on each face.
+ AccessMode locked_levels_[NUMBER_OF_FACES][kMaxLevels];
+
O3D_DECL_CLASS(TextureCUBE, Texture);
DISALLOW_COPY_AND_ASSIGN(TextureCUBE);
};
diff --git a/o3d/core/cross/texture_base.h b/o3d/core/cross/texture_base.h
index 7b64a94..e6d0fce 100644
--- a/o3d/core/cross/texture_base.h
+++ b/o3d/core/cross/texture_base.h
@@ -65,6 +65,14 @@ class Texture : public ParamObject {
DXT5
};
+ // Defines how you want to access a texture when locking.
+ enum AccessMode {
+ kNone = 0,
+ kReadOnly = 1,
+ kWriteOnly = 2,
+ kReadWrite = 3,
+ };
+
typedef unsigned RGBASwizzleIndices[4];
// This is the maximum texture size we allow and hence the largest
@@ -74,7 +82,8 @@ class Texture : public ParamObject {
// NOTE: class Bitmap supports a larger size. The plan is to expose Bitmap
// to Javascript so you can download larger images, scale them, then put
// them in a texture.
- static const int MAX_DIMENSION = 2048;
+ static const int kMaxDimension = 2048;
+ static const int kMaxLevels = 12;
Texture(ServiceLocator* service_locator,
Format format,
diff --git a/o3d/core/cross/texture_test.cc b/o3d/core/cross/texture_test.cc
index 4e55d2e..ba6e93c 100644
--- a/o3d/core/cross/texture_test.cc
+++ b/o3d/core/cross/texture_test.cc
@@ -42,7 +42,7 @@ namespace o3d {
namespace {
bool CompareTexture(Texture2D* texture, int level, const uint8* expected) {
- Texture2D::LockHelper helper(texture, level);
+ Texture2D::LockHelper helper(texture, level, Texture::kReadOnly);
const uint8* data = helper.GetDataAs<const uint8>();
unsigned mip_width = image::ComputeMipDimension(level, texture->width());
unsigned mip_height = image::ComputeMipDimension(level, texture->height());
@@ -90,6 +90,8 @@ TEST_F(Texture2DTest, Basic) {
EXPECT_EQ(texture->format(), Texture::ARGB8);
EXPECT_EQ(texture->levels(), 1);
EXPECT_FALSE(texture->render_surfaces_enabled());
+ EXPECT_EQ(0, Texture::kMaxDimension >> Texture::kMaxLevels);
+ EXPECT_EQ(1, Texture::kMaxDimension >> (Texture::kMaxLevels - 1));
}
TEST_F(Texture2DTest, SetRect) {
diff --git a/o3d/core/win/d3d9/texture_d3d9.cc b/o3d/core/win/d3d9/texture_d3d9.cc
index 68ca0bc..8cb411c 100644
--- a/o3d/core/win/d3d9/texture_d3d9.cc
+++ b/o3d/core/win/d3d9/texture_d3d9.cc
@@ -416,7 +416,7 @@ Texture2DD3D9* Texture2DD3D9::Create(ServiceLocator* service_locator,
if (enable_render_surfaces) {
texture->GetRenderSurface(level);
} else if (!texture->IsCompressed()) {
- texture->SetRect(level, 0, 0,
+ texture->SetRect(level, 0, 0,
image::ComputeMipDimension(level, width),
image::ComputeMipDimension(level, height),
zero.get(), 0);
@@ -574,26 +574,12 @@ void Texture2DD3D9::SetRect(int level,
// Locks the given mipmap level of this texture for loading from main memory,
// and returns a pointer to the buffer.
-bool Texture2DD3D9::Lock(int level, void** texture_data, int* pitch) {
+bool Texture2DD3D9::PlatformSpecificLock(
+ int level, void** texture_data, int* pitch, Texture::AccessMode mode) {
DCHECK(texture_data);
DCHECK(pitch);
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to lock inexistent level " << level << " on Texture \""
- << name() << "\"";
- return false;
- }
- if (IsLocked(level)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is already locked.";
- return false;
- }
- if (render_surfaces_enabled()) {
- O3D_ERROR(service_locator())
- << "Attempting to lock a render-target texture: " << name();
- return false;
- }
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
unsigned int mip_width = image::ComputeMipDimension(level, width());
unsigned int mip_height = image::ComputeMipDimension(level, height());
@@ -602,19 +588,17 @@ bool Texture2DD3D9::Lock(int level, void** texture_data, int* pitch) {
DCHECK(backing_bitmap_->image_data());
*texture_data = backing_bitmap_->GetMipData(level);
*pitch = image::ComputePitch(format(), mip_width);
- locked_levels_ |= 1 << level;
return true;
} else {
RECT rect = {0, 0, mip_width, mip_height};
D3DLOCKED_RECT out_rect = {0};
- if (HR(d3d_texture_->LockRect(level, &out_rect, &rect, 0))) {
+ if (HR(d3d_texture_->LockRect(level, &out_rect, &rect,
+ mode == kReadOnly ? D3DLOCK_READONLY : 0))) {
*texture_data = out_rect.pBits;
*pitch = out_rect.Pitch;
- locked_levels_ |= 1 << level;
return true;
} else {
- O3D_ERROR(service_locator()) << "Failed to Lock Texture2D (D3D9)";
*texture_data = NULL;
return false;
}
@@ -622,19 +606,10 @@ bool Texture2DD3D9::Lock(int level, void** texture_data, int* pitch) {
}
// Unlocks the given mipmap level of this texture.
-bool Texture2DD3D9::Unlock(int level) {
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to unlock inexistent level " << level << " on Texture \""
- << name() << "\"";
- return false;
- }
- if (!IsLocked(level)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is not locked.";
- return false;
- }
+bool Texture2DD3D9::PlatformSpecificUnlock(int level) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+
bool result = false;
if (resize_to_pot_) {
UpdateBackedMipLevel(level);
@@ -642,11 +617,6 @@ bool Texture2DD3D9::Unlock(int level) {
} else {
result = HR(d3d_texture_->UnlockRect(level));
}
- if (result) {
- locked_levels_ &= ~(1 << level);
- } else {
- O3D_ERROR(service_locator()) << "Failed to Unlock Texture2D (D3D9)";
- }
return result;
}
@@ -758,7 +728,7 @@ TextureCUBED3D9* TextureCUBED3D9::Create(ServiceLocator* service_locator,
if (enable_render_surfaces) {
texture->GetRenderSurface(static_cast<CubeFace>(face), level);
} else if (!texture->IsCompressed()) {
- texture->SetRect(static_cast<CubeFace>(face),level , 0, 0,
+ texture->SetRect(static_cast<CubeFace>(face),level , 0, 0,
image::ComputeMipDimension(level, edge_length),
image::ComputeMipDimension(level, edge_length),
zero.get(), 0);
@@ -774,14 +744,6 @@ TextureCUBED3D9* TextureCUBED3D9::Create(ServiceLocator* service_locator,
// Destructor releases the D3D9 texture resource.
TextureCUBED3D9::~TextureCUBED3D9() {
- for (unsigned int i = 0; i < 6; ++i) {
- if (locked_levels_[i] != 0) {
- O3D_ERROR(service_locator())
- << "TextureCUBE \"" << name() << "\" was never unlocked before "
- << "being destroyed.";
- break; // No need to report it more than once.
- }
- }
d3d_cube_texture_ = NULL;
}
@@ -941,27 +903,13 @@ void TextureCUBED3D9::SetRect(TextureCUBE::CubeFace face,
// Locks the given face and mipmap level of this texture for loading from
// main memory, and returns a pointer to the buffer.
-bool TextureCUBED3D9::Lock(
- CubeFace face, int level, void** texture_data, int* pitch) {
+bool TextureCUBED3D9::PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ Texture::AccessMode mode) {
DCHECK(texture_data);
DCHECK(pitch);
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to lock inexistent level " << level << " on Texture \""
- << name();
- return false;
- }
- if (IsLocked(level, face)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " Face " << face << " of texture \"" << name()
- << "\" is already locked.";
- return false;
- }
- if (render_surfaces_enabled()) {
- O3D_ERROR(service_locator())
- << "Attempting to lock a render-target texture: " << name();
- return false;
- }
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
unsigned int mip_width = image::ComputeMipDimension(level, edge_length());
unsigned int mip_height = mip_width;
@@ -971,20 +919,19 @@ bool TextureCUBED3D9::Lock(
DCHECK(backing_bitmap->image_data());
*texture_data = backing_bitmap->GetMipData(level);
*pitch = image::ComputePitch(format(), mip_width);
- locked_levels_[face] |= 1 << level;
return true;
} else {
RECT rect = {0, 0, mip_width, mip_height};
D3DLOCKED_RECT out_rect = {0};
- if (HR(d3d_cube_texture_->LockRect(DX9CubeFace(face), level,
- &out_rect, &rect, 0))) {
+ if (HR(d3d_cube_texture_->LockRect(
+ DX9CubeFace(face), level,
+ &out_rect, &rect,
+ mode == kReadOnly ? D3DLOCK_READONLY : 0))) {
*texture_data = out_rect.pBits;
*pitch = out_rect.Pitch;
- locked_levels_[face] |= 1 << level;
return true;
} else {
- O3D_ERROR(service_locator()) << "Failed to Lock Texture2D (D3D9)";
*texture_data = NULL;
return false;
}
@@ -992,31 +939,15 @@ bool TextureCUBED3D9::Lock(
}
// Unlocks the given face and mipmap level of this texture.
-bool TextureCUBED3D9::Unlock(CubeFace face, int level) {
- if (level >= levels() || level < 0) {
- O3D_ERROR(service_locator())
- << "Trying to unlock inexistent level " << level << " on Texture \""
- << name();
- return false;
- }
- if (!IsLocked(level, face)) {
- O3D_ERROR(service_locator())
- << "Level " << level << " of texture \"" << name()
- << "\" is not locked.";
- return false;
- }
+bool TextureCUBED3D9::PlatformSpecificUnlock(CubeFace face, int level) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
bool result = false;
if (resize_to_pot_) {
UpdateBackedMipLevel(face, level);
result = true;
} else {
- result = HR(d3d_cube_texture_->UnlockRect(DX9CubeFace(face),
- level));
- }
- if (result) {
- locked_levels_[face] &= ~(1 << level);
- } else {
- O3D_ERROR(service_locator()) << "Failed to Unlock Texture2D (D3D9)";
+ result = HR(d3d_cube_texture_->UnlockRect(DX9CubeFace(face), level));
}
return result;
}
diff --git a/o3d/core/win/d3d9/texture_d3d9.h b/o3d/core/win/d3d9/texture_d3d9.h
index c8c948b..8f53ffe 100644
--- a/o3d/core/win/d3d9/texture_d3d9.h
+++ b/o3d/core/win/d3d9/texture_d3d9.h
@@ -92,10 +92,11 @@ class Texture2DD3D9 : public Texture2D {
protected:
// Overridden from Texture2D
- virtual bool Lock(int level, void** texture_data, int* pitch);
+ virtual bool PlatformSpecificLock(
+ int level, void** texture_data, int* pitch, AccessMode mode);
// Overridden from Texture2D
- virtual bool Unlock(int level);
+ virtual bool PlatformSpecificUnlock(int level);
// Overridden from Texture2D
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(int mip_level);
@@ -170,10 +171,12 @@ class TextureCUBED3D9 : public TextureCUBE {
protected:
// Overridden from TextureCUBE
- bool Lock(CubeFace face, int level, void** texture_data, int* pitch);
+ virtual bool PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode);
// Overridden from TextureCUBE
- bool Unlock(CubeFace face, int level);
+ virtual bool PlatformSpecificUnlock(CubeFace face, int level);
// Overridden from TextureCUBE.
virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(CubeFace face,
diff --git a/o3d/plugin/cross/texture_static_glue.cc b/o3d/plugin/cross/texture_static_glue.cc
index 94d29f9..08d27b2 100644
--- a/o3d/plugin/cross/texture_static_glue.cc
+++ b/o3d/plugin/cross/texture_static_glue.cc
@@ -234,7 +234,7 @@ void SetRectCheck2D(o3d::Texture2D* self,
return;
}
}
- o3d::Texture2D::LockHelper helper(self, level);
+ o3d::Texture2D::LockHelper helper(self, level, o3d::Texture::kWriteOnly);
void* data = helper.GetData();
if (!data) {
O3D_ERROR(self->service_locator()) << "could not lock texture";
@@ -310,7 +310,8 @@ void SetRectCheckCUBE(o3d::TextureCUBE* self,
return;
}
}
- o3d::TextureCUBE::LockHelper helper(self, face, level);
+ o3d::TextureCUBE::LockHelper helper(
+ self, face, level, o3d::Texture::kWriteOnly);
void* data = helper.GetData();
if (!data) {
O3D_ERROR(self->service_locator()) << "could not lock texture";
@@ -494,7 +495,7 @@ std::vector<float> userglue_method_GetRect(o3d::Texture2D* self,
<< "Texture::Set not supported for this type of texture";
return empty;
}
- o3d::Texture2D::LockHelper helper(self, level);
+ o3d::Texture2D::LockHelper helper(self, level, o3d::Texture::kReadOnly);
void* data = helper.GetData();
if (!data) {
O3D_ERROR(self->service_locator()) << "could not lock texture";
@@ -580,7 +581,8 @@ std::vector<float> userglue_method_GetRect(o3d::TextureCUBE* self,
<< "Texture::Set not supported for this type of texture";
return empty;
}
- o3d::TextureCUBE::LockHelper helper(self, face, level);
+ o3d::TextureCUBE::LockHelper helper(
+ self, face, level, o3d::Texture::kReadOnly);
void* data = helper.GetData();
if (!data) {
O3D_ERROR(self->service_locator()) << "could not lock texture";