summaryrefslogtreecommitdiffstats
path: root/o3d/core/cross
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/core/cross')
-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
10 files changed, 346 insertions, 213 deletions
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) {