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
master
hybrid 2010-12-14 23:32:54 +00:00
parent 54ff5773af
commit d9c9de5158
17 changed files with 93 additions and 70 deletions

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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 )
{

View File

@ -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 )
{

View File

@ -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<s32>&
{
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<s32>&
core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));
if (!clamped.isValid())
return 0;
u8* src = static_cast<u8*>(texture->lock(true));
u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));
if (!src)
return 0;
IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());

View File

@ -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<u32>& getOriginalSize() const { return size; }
virtual const core::dimension2d<u32>& getSize() const { return size; }

View File

@ -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<u8*>(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<u8*>(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();
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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();