From d9c9de51588c2967aadf349b5d84ba17a23711bc Mon Sep 17 00:00:00 2001 From: hybrid Date: Tue, 14 Dec 2010 23:32:54 +0000 Subject: [PATCH] Add a new texture lock mode for write-only access. The lock method has changed for this. Support is only implemented under OpenGL so far. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@3510 dfc29bdd-3216-0410-991c-e03cc46cb475 --- changes.txt | 2 + include/ITexture.h | 24 +++++++- source/Irrlicht/CD3D8Texture.cpp | 4 +- source/Irrlicht/CD3D8Texture.h | 2 +- source/Irrlicht/CD3D9Texture.cpp | 6 +- source/Irrlicht/CD3D9Texture.h | 2 +- source/Irrlicht/CIrrDeviceLinux.cpp | 4 +- source/Irrlicht/CIrrDeviceWin32.cpp | 2 +- source/Irrlicht/CNullDriver.cpp | 8 +-- source/Irrlicht/CNullDriver.h | 2 +- source/Irrlicht/COpenGLTexture.cpp | 87 ++++++++++++++-------------- source/Irrlicht/COpenGLTexture.h | 2 +- source/Irrlicht/CSoftwareTexture.cpp | 2 +- source/Irrlicht/CSoftwareTexture.h | 2 +- source/Irrlicht/CSoftwareTexture2.h | 2 +- source/Irrlicht/IBurningShader.cpp | 2 +- tests/textureFeatures.cpp | 10 ++-- 17 files changed, 93 insertions(+), 70 deletions(-) diff --git a/changes.txt b/changes.txt index c579c542..cb0818c9 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,7 @@ Changes in 1.8 (??.0?.2010) + - API change: Added write only lock mode for textures. The lock method has changed the signature and uses an enum parameter now instead of a bool. The default is still to lock for read/write (previously 'false'). The old 'true' value should be replaced by ETLM_READ_ONLY. + - Speedup deleting of particles - Add function IParticleSystemSceneNode::clearParticles diff --git a/include/ITexture.h b/include/ITexture.h index 227fbf37..553ec3cb 100644 --- a/include/ITexture.h +++ b/include/ITexture.h @@ -70,6 +70,21 @@ enum E_TEXTURE_CREATION_FLAG ETCF_FORCE_32_BIT_DO_NOT_USE = 0x7fffffff }; +//! Enum for the mode for texture locking. Read-Only, write-only or read/write. +enum E_TEXTURE_LOCK_MODE +{ + //! The default mode. Texture can be read and written to. + ETLM_READ_WRITE = 0, + + //! Read only. The texture is downloaded, but not uploaded again. + /** Often used to read back shader generated textures. */ + ETLM_READ_ONLY, + + //! Write only. The texture is not downloaded and might be uninitialised. + /** The updated texture is uploaded to the GPU. + Used for initialising the shader from the CPU. */ + ETLM_WRITE_ONLY +}; //! Interface of a Video Driver dependent Texture. /** An ITexture is created by an IVideoDriver by using IVideoDriver::addTexture @@ -99,14 +114,17 @@ public: unlocked. The size of the i-th mipmap level is defined as max(getSize().Width>>i,1) and max(getSize().Height>>i,1) - \param readOnly Specifies that no changes to the locked texture are - made. Unspecified behavior will arise if still write access happens. + \param mode Specifies what kind of changes to the locked texture are + allowed. Unspecified behavior will arise if texture is written in read + only mode or read from in write only mode. + Support for this feature depends on the driver, so don't rely on the + texture being write-protected when locking with read-only, etc. \param mipmapLevel Number of the mipmapLevel to lock. 0 is main texture. Non-existing levels will silently fail and return 0. \return Returns a pointer to the pixel data. The format of the pixel can be determined by using getColorFormat(). 0 is returned, if the texture cannot be locked. */ - virtual void* lock(bool readOnly = false, u32 mipmapLevel=0) = 0; + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0) = 0; //! Unlock function. Must be called after a lock() to the texture. /** One should avoid to call unlock more than once before another lock. diff --git a/source/Irrlicht/CD3D8Texture.cpp b/source/Irrlicht/CD3D8Texture.cpp index c0ae62b3..63001d78 100644 --- a/source/Irrlicht/CD3D8Texture.cpp +++ b/source/Irrlicht/CD3D8Texture.cpp @@ -205,7 +205,7 @@ bool CD3D8Texture::copyTexture(video::IImage* image) //! lock function -void* CD3D8Texture::lock(bool readOnly, u32 mipmapLevel) +void* CD3D8Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel) { if (!Texture) return 0; @@ -215,7 +215,7 @@ void* CD3D8Texture::lock(bool readOnly, u32 mipmapLevel) D3DLOCKED_RECT rect; if(!IsRenderTarget) { - hr = Texture->LockRect(mipmapLevel, &rect, 0, readOnly?D3DLOCK_READONLY:0); + hr = Texture->LockRect(mipmapLevel, &rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0); if (FAILED(hr)) { os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR); diff --git a/source/Irrlicht/CD3D8Texture.h b/source/Irrlicht/CD3D8Texture.h index 25ae8eeb..138f7802 100644 --- a/source/Irrlicht/CD3D8Texture.h +++ b/source/Irrlicht/CD3D8Texture.h @@ -38,7 +38,7 @@ public: virtual ~CD3D8Texture(); //! lock function - virtual void* lock(bool readOnly = false, u32 mipmapLevel=0); + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0); //! unlock function virtual void unlock(); diff --git a/source/Irrlicht/CD3D9Texture.cpp b/source/Irrlicht/CD3D9Texture.cpp index ec72c34b..b1b001e3 100644 --- a/source/Irrlicht/CD3D9Texture.cpp +++ b/source/Irrlicht/CD3D9Texture.cpp @@ -383,7 +383,7 @@ bool CD3D9Texture::copyTexture(IImage * image) //! lock function -void* CD3D9Texture::lock(bool readOnly, u32 mipmapLevel) +void* CD3D9Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel) { if (!Texture) return 0; @@ -393,7 +393,7 @@ void* CD3D9Texture::lock(bool readOnly, u32 mipmapLevel) D3DLOCKED_RECT rect; if(!IsRenderTarget) { - hr = Texture->LockRect(mipmapLevel, &rect, 0, readOnly?D3DLOCK_READONLY:0); + hr = Texture->LockRect(mipmapLevel, &rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0); if (FAILED(hr)) { os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR); @@ -429,7 +429,7 @@ void* CD3D9Texture::lock(bool readOnly, u32 mipmapLevel) os::Printer::log("Could not lock DIRECT3D9 Texture", "Data copy failed.", ELL_ERROR); return 0; } - hr = RTTSurface->LockRect(&rect, 0, readOnly?D3DLOCK_READONLY:0); + hr = RTTSurface->LockRect(&rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0); if(FAILED(hr)) { os::Printer::log("Could not lock DIRECT3D9 Texture", "LockRect failed.", ELL_ERROR); diff --git a/source/Irrlicht/CD3D9Texture.h b/source/Irrlicht/CD3D9Texture.h index 19927f1c..35571c41 100644 --- a/source/Irrlicht/CD3D9Texture.h +++ b/source/Irrlicht/CD3D9Texture.h @@ -42,7 +42,7 @@ public: virtual ~CD3D9Texture(); //! lock function - virtual void* lock(bool readOnly = false, u32 mipmapLevel=0); + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0); //! unlock function virtual void unlock(); diff --git a/source/Irrlicht/CIrrDeviceLinux.cpp b/source/Irrlicht/CIrrDeviceLinux.cpp index 53f620bf..8b10b7d0 100644 --- a/source/Irrlicht/CIrrDeviceLinux.cpp +++ b/source/Irrlicht/CIrrDeviceLinux.cpp @@ -1946,7 +1946,7 @@ Cursor CIrrDeviceLinux::TextureToMonochromeCursor(irr::video::ITexture * tex, co u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; - const u8* data = (const u8*)tex->lock(true, 0); + const u8* data = (const u8*)tex->lock(ETLM_READ_ONLY, 0); data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) { @@ -2022,7 +2022,7 @@ Cursor CIrrDeviceLinux::TextureToARGBCursor(irr::video::ITexture * tex, const co u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; XcursorPixel* target = image->pixels; - const u8* data = (const u8*)tex->lock(true, 0); + const u8* data = (const u8*)tex->lock(ETLM_READ_ONLY, 0); data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) { diff --git a/source/Irrlicht/CIrrDeviceWin32.cpp b/source/Irrlicht/CIrrDeviceWin32.cpp index 2ab14fd4..67a31cb7 100644 --- a/source/Irrlicht/CIrrDeviceWin32.cpp +++ b/source/Irrlicht/CIrrDeviceWin32.cpp @@ -1574,7 +1574,7 @@ HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; - const u8* data = (const u8*)tex->lock(true, 0); + const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0); data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) { diff --git a/source/Irrlicht/CNullDriver.cpp b/source/Irrlicht/CNullDriver.cpp index ca8a534f..4c88c401 100644 --- a/source/Irrlicht/CNullDriver.cpp +++ b/source/Irrlicht/CNullDriver.cpp @@ -1086,7 +1086,7 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, if (texture->getColorFormat() == ECF_A1R5G5B5) { - u16 *p = (u16*)texture->lock(true); + u16 *p = (u16*)texture->lock(ETLM_READ_ONLY); if (!p) { @@ -1102,7 +1102,7 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, } else { - u32 *p = (u32*)texture->lock(true); + u32 *p = (u32*)texture->lock(ETLM_READ_ONLY); if (!p) { @@ -1442,7 +1442,7 @@ IImage* CNullDriver::createImage(ITexture* texture, const core::position2d& { if ((pos==core::position2di(0,0)) && (size == texture->getSize())) { - IImage* image = new CImage(texture->getColorFormat(), size, texture->lock(true), false); + IImage* image = new CImage(texture->getColorFormat(), size, texture->lock(ETLM_READ_ONLY), false); texture->unlock(); return image; } @@ -1457,7 +1457,7 @@ IImage* CNullDriver::createImage(ITexture* texture, const core::position2d& core::clamp(static_cast(size.Height), 0u, texture->getSize().Height))); if (!clamped.isValid()) return 0; - u8* src = static_cast(texture->lock(true)); + u8* src = static_cast(texture->lock(ETLM_READ_ONLY)); if (!src) return 0; IImage* image = new CImage(texture->getColorFormat(), clamped.getSize()); diff --git a/source/Irrlicht/CNullDriver.h b/source/Irrlicht/CNullDriver.h index 07e4eccd..54d4b920 100644 --- a/source/Irrlicht/CNullDriver.h +++ b/source/Irrlicht/CNullDriver.h @@ -720,7 +720,7 @@ namespace video { SDummyTexture(const io::path& name) : ITexture(name), size(0,0) {}; - virtual void* lock(bool readOnly = false, u32 mipmapLevel=0) { return 0; }; + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0) { return 0; }; virtual void unlock(){} virtual const core::dimension2d& getOriginalSize() const { return size; } virtual const core::dimension2d& getSize() const { return size; } diff --git a/source/Irrlicht/COpenGLTexture.cpp b/source/Irrlicht/COpenGLTexture.cpp index ff4ef9ed..7a893736 100644 --- a/source/Irrlicht/COpenGLTexture.cpp +++ b/source/Irrlicht/COpenGLTexture.cpp @@ -354,11 +354,11 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level) //! lock function -void* COpenGLTexture::lock(bool readOnly, u32 mipmapLevel) +void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel) { // store info about which image is locked IImage* image = (mipmapLevel==0)?Image:MipImage; - ReadOnlyLock |= readOnly; + ReadOnlyLock |= (mode==ETLM_READ_ONLY); MipLevelStored = mipmapLevel; // if data not available or might have changed on GPU download it @@ -390,48 +390,51 @@ void* COpenGLTexture::lock(bool readOnly, u32 mipmapLevel) if (!image) return 0; - u8* pixels = static_cast(image->lock()); - if (!pixels) - return 0; - - // we need to keep the correct texture bound later on - GLint tmpTexture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture); - glBindTexture(GL_TEXTURE_2D, TextureName); - - // allows to read pixels in top-to-bottom order -#ifdef GL_MESA_pack_invert - if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert)) - glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); -#endif - - // download GPU data as ARGB8 to pixels; - glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); - -#ifdef GL_MESA_pack_invert - if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert)) - glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); - else -#endif + if (mode != ETLM_WRITE_ONLY) { - // opengl images are horizontally flipped, so we have to fix that here. - const s32 pitch=image->getPitch(); - u8* p2 = pixels + (image->getDimension().Height - 1) * pitch; - u8* tmpBuffer = new u8[pitch]; - for (u32 i=0; i < image->getDimension().Height; i += 2) - { - memcpy(tmpBuffer, pixels, pitch); - memcpy(pixels, p2, pitch); - memcpy(p2, tmpBuffer, pitch); - pixels += pitch; - p2 -= pitch; - } - delete [] tmpBuffer; - } - image->unlock(); + u8* pixels = static_cast(image->lock()); + if (!pixels) + return 0; - //reset old bound texture - glBindTexture(GL_TEXTURE_2D, tmpTexture); + // we need to keep the correct texture bound later on + GLint tmpTexture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture); + glBindTexture(GL_TEXTURE_2D, TextureName); + + // allows to read pixels in top-to-bottom order + #ifdef GL_MESA_pack_invert + if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert)) + glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); + #endif + + // download GPU data as ARGB8 to pixels; + glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); + + #ifdef GL_MESA_pack_invert + if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert)) + glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); + else + #endif + { + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch=image->getPitch(); + u8* p2 = pixels + (image->getDimension().Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (u32 i=0; i < image->getDimension().Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); + memcpy(pixels, p2, pitch); + memcpy(p2, tmpBuffer, pitch); + pixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + } + image->unlock(); + + //reset old bound texture + glBindTexture(GL_TEXTURE_2D, tmpTexture); + } } return image->lock(); } diff --git a/source/Irrlicht/COpenGLTexture.h b/source/Irrlicht/COpenGLTexture.h index 47ac6481..89ba94c6 100644 --- a/source/Irrlicht/COpenGLTexture.h +++ b/source/Irrlicht/COpenGLTexture.h @@ -57,7 +57,7 @@ public: virtual ~COpenGLTexture(); //! lock function - virtual void* lock(bool readOnly=false, u32 mipmapLevel=0); + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0); //! unlock function virtual void unlock(); diff --git a/source/Irrlicht/CSoftwareTexture.cpp b/source/Irrlicht/CSoftwareTexture.cpp index 4273b29a..7bb8883d 100644 --- a/source/Irrlicht/CSoftwareTexture.cpp +++ b/source/Irrlicht/CSoftwareTexture.cpp @@ -58,7 +58,7 @@ CSoftwareTexture::~CSoftwareTexture() //! lock function -void* CSoftwareTexture::lock(bool readOnly, u32 mipmapLevel) +void* CSoftwareTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel) { return Image->lock(); } diff --git a/source/Irrlicht/CSoftwareTexture.h b/source/Irrlicht/CSoftwareTexture.h index f5cdd10e..6d2b30dd 100644 --- a/source/Irrlicht/CSoftwareTexture.h +++ b/source/Irrlicht/CSoftwareTexture.h @@ -28,7 +28,7 @@ public: virtual ~CSoftwareTexture(); //! lock function - virtual void* lock(bool readOnly = false, u32 mipmapLevel=0); + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0); //! unlock function virtual void unlock(); diff --git a/source/Irrlicht/CSoftwareTexture2.h b/source/Irrlicht/CSoftwareTexture2.h index f58a7627..8e123da0 100644 --- a/source/Irrlicht/CSoftwareTexture2.h +++ b/source/Irrlicht/CSoftwareTexture2.h @@ -36,7 +36,7 @@ public: virtual ~CSoftwareTexture2(); //! lock function - virtual void* lock(bool readOnly = false, u32 mipmapLevel=0) + virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0) { if (Flags & GEN_MIPMAP) MipMapLOD=mipmapLevel; diff --git a/source/Irrlicht/IBurningShader.cpp b/source/Irrlicht/IBurningShader.cpp index 3045a0d4..6edcde06 100644 --- a/source/Irrlicht/IBurningShader.cpp +++ b/source/Irrlicht/IBurningShader.cpp @@ -101,7 +101,7 @@ namespace video // select mignify and magnify ( lodLevel ) //SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS it->lodLevel = lodLevel; - it->data = (tVideoSample*) it->Texture->lock(true, + it->data = (tVideoSample*) it->Texture->lock(ETLM_READ_ONLY, core::s32_clamp ( lodLevel + SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS, 0, SOFTWARE_DRIVER_2_MIPMAPPING_MAX - 1 )); // prepare for optimal fixpoint diff --git a/tests/textureFeatures.cpp b/tests/textureFeatures.cpp index b2859253..51f9b2f9 100644 --- a/tests/textureFeatures.cpp +++ b/tests/textureFeatures.cpp @@ -55,19 +55,19 @@ static bool lockAllMipLevels(video::E_DRIVER_TYPE driverType) driver->endScene(); video::ITexture* tex = driver->findTexture("miptest"); - video::SColor* bits = (video::SColor*)tex->lock(true, 0); + video::SColor* bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 0); result |= (bits[0].color==0xff0000ff); tex->unlock(); - bits = (video::SColor*)tex->lock(true, 1); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 1); result |= (bits[0].color==0x00ff00ff); tex->unlock(); - bits = (video::SColor*)tex->lock(true, 2); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 2); result |= (bits[0].color==0x0000ffff); tex->unlock(); - bits = (video::SColor*)tex->lock(true, 3); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 3); result |= (bits[0].color==0xc2c200ff); tex->unlock(); - bits = (video::SColor*)tex->lock(true, 4); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 4); result |= (bits[0].color==0x001212ff); tex->unlock();