diff options
Diffstat (limited to 'o3d/core/cross')
-rw-r--r-- | o3d/core/cross/canvas.cc | 2 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/texture_cb.cc | 100 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/texture_cb.h | 22 | ||||
-rw-r--r-- | o3d/core/cross/gl/texture_gl.cc | 107 | ||||
-rw-r--r-- | o3d/core/cross/gl/texture_gl.h | 21 | ||||
-rw-r--r-- | o3d/core/cross/pack.cc | 28 | ||||
-rw-r--r-- | o3d/core/cross/texture.cc | 199 | ||||
-rw-r--r-- | o3d/core/cross/texture.h | 65 | ||||
-rw-r--r-- | o3d/core/cross/texture_base.h | 11 | ||||
-rw-r--r-- | o3d/core/cross/texture_test.cc | 4 |
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) {
|