Support redefinition of textures through glTexImage2D.

TRAC #11316. Keep a dirty data flag, recreate the texture when it is set. Texture now owns getTexture() and calls a virtual createTexture method when the derived classes need to recreate. Signed-off-by: Daniel Koch Author: Andrew Lewycky <andrew.lewycky@transgaming.com> git-svn-id: https://angleproject.googlecode.com/svn/trunk@12 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent fab5a1ae
...@@ -24,6 +24,8 @@ Texture::Texture() : Colorbuffer(0) ...@@ -24,6 +24,8 @@ Texture::Texture() : Colorbuffer(0)
mMagFilter = GL_LINEAR; mMagFilter = GL_LINEAR;
mWrapS = GL_REPEAT; mWrapS = GL_REPEAT;
mWrapT = GL_REPEAT; mWrapT = GL_REPEAT;
mDirtyImageData = true;
} }
Texture::~Texture() Texture::~Texture()
...@@ -113,24 +115,24 @@ GLenum Texture::getWrapT() ...@@ -113,24 +115,24 @@ GLenum Texture::getWrapT()
} }
// Copies an Image into an already locked Direct3D 9 surface, performing format conversions as necessary // Copies an Image into an already locked Direct3D 9 surface, performing format conversions as necessary
void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image) void Texture::copyImage(const D3DLOCKED_RECT &lock, D3DFORMAT format, Image *image)
{ {
if (lock.pBits && image.pixels) if (lock.pBits && !image->pixels.empty())
{ {
for (int y = 0; y < image.height; y++) for (int y = 0; y < image->height; y++)
{ {
unsigned char *source = (unsigned char*)image.pixels + y * image.width * pixelSize(image); unsigned char *source = &image->pixels[0] + y * image->width * pixelSize(*image);
unsigned short *source16 = (unsigned short*)source; unsigned short *source16 = (unsigned short*)source;
unsigned char *dest = (unsigned char*)lock.pBits + y * lock.Pitch; unsigned char *dest = (unsigned char*)lock.pBits + y * lock.Pitch;
for (int x = 0; x < image.width; x++) for (int x = 0; x < image->width; x++)
{ {
unsigned char r; unsigned char r;
unsigned char g; unsigned char g;
unsigned char b; unsigned char b;
unsigned char a; unsigned char a;
switch (image.format) switch (image->format)
{ {
case GL_ALPHA: case GL_ALPHA:
UNIMPLEMENTED(); UNIMPLEMENTED();
...@@ -142,7 +144,7 @@ void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image) ...@@ -142,7 +144,7 @@ void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image)
UNIMPLEMENTED(); UNIMPLEMENTED();
break; break;
case GL_RGB: case GL_RGB:
switch (image.type) switch (image->type)
{ {
case GL_UNSIGNED_BYTE: UNIMPLEMENTED(); break; case GL_UNSIGNED_BYTE: UNIMPLEMENTED(); break;
case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5:
...@@ -159,7 +161,7 @@ void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image) ...@@ -159,7 +161,7 @@ void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image)
} }
break; break;
case GL_RGBA: case GL_RGBA:
switch (image.type) switch (image->type)
{ {
case GL_UNSIGNED_BYTE: case GL_UNSIGNED_BYTE:
r = source[x * 4 + 0]; r = source[x * 4 + 0];
...@@ -262,23 +264,52 @@ int Texture::pixelSize(const Image &image) ...@@ -262,23 +264,52 @@ int Texture::pixelSize(const Image &image)
return 0; return 0;
} }
Texture2D::Texture2D() void Texture::setImage(GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img)
{ {
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) mDirtyImageData = true;
img->internalFormat = internalFormat;
img->width = width;
img->height = height;
img->format = format;
img->type = type;
size_t imageSize = pixelSize(*img) * width * height;
std::vector<unsigned char> storage(imageSize);
if (pixels)
{ {
mImageArray[level].pixels = NULL; memcpy(&storage[0], pixels, imageSize);
} }
mTexture = NULL; img->pixels.swap(storage);
} }
Texture2D::~Texture2D() IDirect3DBaseTexture9 *Texture::getTexture()
{ {
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) if (!isComplete())
{ {
delete[] mImageArray[level].pixels; return NULL;
} }
if (mDirtyImageData)
{
mBaseTexture = createTexture();
mDirtyImageData = false;
}
return mBaseTexture;
}
Texture2D::Texture2D()
{
mTexture = NULL;
}
Texture2D::~Texture2D()
{
if (mTexture) if (mTexture)
{ {
mTexture->Release(); mTexture->Release();
...@@ -298,22 +329,7 @@ void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsi ...@@ -298,22 +329,7 @@ void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsi
return; return;
} }
mImageArray[level].internalFormat = internalFormat; Texture::setImage(internalFormat, width, height, format, type, pixels, &mImageArray[level]);
mImageArray[level].width = width;
mImageArray[level].height = height;
mImageArray[level].format = format;
mImageArray[level].type = type;
delete[] mImageArray[level].pixels;
mImageArray[level].pixels = NULL;
int imageSize = pixelSize(mImageArray[level]) * width * height;
mImageArray[level].pixels = new unsigned char[imageSize];
if (pixels)
{
memcpy(mImageArray[level].pixels, pixels, imageSize);
}
if (level == 0) if (level == 0)
{ {
...@@ -384,63 +400,63 @@ bool Texture2D::isComplete() ...@@ -384,63 +400,63 @@ bool Texture2D::isComplete()
} }
// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one // Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
IDirect3DBaseTexture9 *Texture2D::getTexture() IDirect3DBaseTexture9 *Texture2D::createTexture()
{ {
if (!isComplete()) IDirect3DTexture9 *texture;
{
return NULL;
}
if (!mTexture) // FIXME: Recreate when changed (same for getRenderTarget) IDirect3DDevice9 *device = getDevice();
{ D3DFORMAT format = selectFormat(mImageArray[0]);
IDirect3DDevice9 *device = getDevice();
D3DFORMAT format = selectFormat(mImageArray[0]);
HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &mTexture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
{
error(GL_OUT_OF_MEMORY, 0);
}
ASSERT(SUCCEEDED(result)); if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
IDirect3DTexture9 *lockableTexture; ASSERT(SUCCEEDED(result));
result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) IDirect3DTexture9 *lockableTexture;
{ result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
error(GL_OUT_OF_MEMORY,(IDirect3DBaseTexture9*)NULL);
}
ASSERT(SUCCEEDED(result)); if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
texture->Release();
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
if (mTexture) // FIXME: Handle failure ASSERT(SUCCEEDED(result));
{
int levelCount = mTexture->GetLevelCount();
for (int level = 0; level < levelCount; level++) int levelCount = texture->GetLevelCount();
{
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect(level, &lock, NULL, 0);
copyImage(lock, format, mImageArray[level]); for (int level = 0; level < levelCount; level++)
{
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect(level, &lock, NULL, 0);
lockableTexture->UnlockRect(level); copyImage(lock, format, &mImageArray[level]);
}
device->UpdateTexture(lockableTexture, mTexture); lockableTexture->UnlockRect(level);
lockableTexture->Release();
}
} }
return mTexture; device->UpdateTexture(lockableTexture, texture);
lockableTexture->Release();
if (mTexture) mTexture->Release();
mTexture = texture;
return texture;
} }
// Returns the top-level texture surface as a render target // Returns the top-level texture surface as a render target
IDirect3DSurface9 *Texture2D::getRenderTarget() IDirect3DSurface9 *Texture2D::getRenderTarget()
{ {
if (!mRenderTarget && getTexture()) if (mDirtyImageData && mRenderTarget)
{
mRenderTarget->Release();
mRenderTarget = NULL;
}
if (!mRenderTarget && getTexture()) // FIXME: getTexture fails for incomplete textures. Check spec.
{ {
mTexture->GetSurfaceLevel(0, &mRenderTarget); mTexture->GetSurfaceLevel(0, &mRenderTarget);
} }
...@@ -450,27 +466,11 @@ IDirect3DSurface9 *Texture2D::getRenderTarget() ...@@ -450,27 +466,11 @@ IDirect3DSurface9 *Texture2D::getRenderTarget()
TextureCubeMap::TextureCubeMap() TextureCubeMap::TextureCubeMap()
{ {
for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
mImageArray[face][level].pixels = NULL;
}
}
mTexture = NULL; mTexture = NULL;
} }
TextureCubeMap::~TextureCubeMap() TextureCubeMap::~TextureCubeMap()
{ {
for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
delete[] mImageArray[face][level].pixels;
}
}
if (mTexture) if (mTexture)
{ {
mTexture->Release(); mTexture->Release();
...@@ -586,57 +586,52 @@ bool TextureCubeMap::isComplete() ...@@ -586,57 +586,52 @@ bool TextureCubeMap::isComplete()
} }
// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one // Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
IDirect3DBaseTexture9 *TextureCubeMap::getTexture() IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
{ {
if (!isComplete()) IDirect3DDevice9 *device = getDevice();
{ D3DFORMAT format = selectFormat(mImageArray[0][0]);
return NULL;
}
if (!mTexture) // FIXME: Recreate when changed (same for getRenderTarget) IDirect3DCubeTexture9 *texture;
{
IDirect3DDevice9 *device = getDevice();
D3DFORMAT format = selectFormat(mImageArray[0][0]);
HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &mTexture, NULL); HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{ {
error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
} }
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
IDirect3DCubeTexture9 *lockableTexture; IDirect3DCubeTexture9 *lockableTexture;
result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL); result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{ {
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); texture->Release();
} return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
if (mTexture) for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{ {
for (int face = 0; face < 6; face++) D3DLOCKED_RECT lock = {0};
{ lockableTexture->LockRect((D3DCUBEMAP_FACES)face, level, &lock, NULL, 0);
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect((D3DCUBEMAP_FACES)face, level, &lock, NULL, 0);
copyImage(lock, format, mImageArray[face][level]);
lockableTexture->UnlockRect((D3DCUBEMAP_FACES)face, level); copyImage(lock, format, &mImageArray[face][level]);
}
}
device->UpdateTexture(lockableTexture, mTexture); lockableTexture->UnlockRect((D3DCUBEMAP_FACES)face, level);
lockableTexture->Release();
} }
} }
device->UpdateTexture(lockableTexture, texture);
lockableTexture->Release();
if (mTexture) mTexture->Release();
mTexture = texture;
return mTexture; return mTexture;
} }
...@@ -647,22 +642,7 @@ void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsi ...@@ -647,22 +642,7 @@ void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsi
return; return;
} }
mImageArray[face][level].internalFormat = internalFormat; Texture::setImage(internalFormat, width, height, format, type, pixels, &mImageArray[face][level]);
mImageArray[face][level].width = width;
mImageArray[face][level].height = height;
mImageArray[face][level].format = format;
mImageArray[face][level].type = type;
delete[] mImageArray[face][level].pixels;
mImageArray[face][level].pixels = NULL;
int imageSize = pixelSize(mImageArray[face][level]) * width * height;
mImageArray[face][level].pixels = new unsigned char[imageSize];
if (pixels)
{
memcpy(mImageArray[face][level].pixels, pixels, imageSize);
}
if (face == 0 && level == 0) if (face == 0 && level == 0)
{ {
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <d3d9.h> #include <d3d9.h>
#include <vector>
namespace gl namespace gl
{ {
enum enum
...@@ -27,17 +29,6 @@ enum ...@@ -27,17 +29,6 @@ enum
MAX_TEXTURE_LEVELS = 11 // log2 of MAX_TEXTURE_SIZE MAX_TEXTURE_LEVELS = 11 // log2 of MAX_TEXTURE_SIZE
}; };
// Helper structure representing a single image layer
struct Image
{
GLenum internalFormat;
GLsizei width;
GLsizei height;
GLenum format;
GLenum type;
void *pixels;
};
class Texture : public Colorbuffer class Texture : public Colorbuffer
{ {
public: public:
...@@ -58,10 +49,22 @@ class Texture : public Colorbuffer ...@@ -58,10 +49,22 @@ class Texture : public Colorbuffer
GLenum getWrapT(); GLenum getWrapT();
virtual bool isComplete() = 0; virtual bool isComplete() = 0;
virtual IDirect3DBaseTexture9 *getTexture() = 0; IDirect3DBaseTexture9 *getTexture();
protected: protected:
void copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image); // Helper structure representing a single image layer
struct Image
{
GLenum internalFormat;
GLsizei width;
GLsizei height;
GLenum format;
GLenum type;
std::vector<unsigned char> pixels;
};
void copyImage(const D3DLOCKED_RECT &lock, D3DFORMAT format, Image *image);
static D3DFORMAT selectFormat(const Image &image); static D3DFORMAT selectFormat(const Image &image);
static int pixelSize(const Image &image); static int pixelSize(const Image &image);
...@@ -71,8 +74,17 @@ class Texture : public Colorbuffer ...@@ -71,8 +74,17 @@ class Texture : public Colorbuffer
GLenum mWrapS; GLenum mWrapS;
GLenum mWrapT; GLenum mWrapT;
void setImage(GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img);
// The pointer returned is weak and it is assumed the derived class will keep a strong pointer until the next createTexture() call.
virtual IDirect3DBaseTexture9 *createTexture() = 0;
bool mDirtyImageData; // FIXME: would be private but getRenderTarget is still implemented through the derived classes and they need it.
private: private:
DISALLOW_COPY_AND_ASSIGN(Texture); DISALLOW_COPY_AND_ASSIGN(Texture);
IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer.
}; };
class Texture2D : public Texture class Texture2D : public Texture
...@@ -97,12 +109,13 @@ class Texture2D : public Texture ...@@ -97,12 +109,13 @@ class Texture2D : public Texture
GLenum getWrapT(); GLenum getWrapT();
bool isComplete(); bool isComplete();
IDirect3DBaseTexture9 *getTexture();
IDirect3DSurface9 *getRenderTarget(); IDirect3DSurface9 *getRenderTarget();
private: private:
DISALLOW_COPY_AND_ASSIGN(Texture2D); DISALLOW_COPY_AND_ASSIGN(Texture2D);
virtual IDirect3DBaseTexture9 *createTexture();
Image mImageArray[MAX_TEXTURE_LEVELS]; Image mImageArray[MAX_TEXTURE_LEVELS];
IDirect3DTexture9 *mTexture; IDirect3DTexture9 *mTexture;
...@@ -125,11 +138,12 @@ class TextureCubeMap : public Texture ...@@ -125,11 +138,12 @@ class TextureCubeMap : public Texture
void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
bool isComplete(); bool isComplete();
IDirect3DBaseTexture9 *getTexture();
private: private:
DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); DISALLOW_COPY_AND_ASSIGN(TextureCubeMap);
virtual IDirect3DBaseTexture9 *createTexture();
void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
Image mImageArray[6][MAX_TEXTURE_LEVELS]; Image mImageArray[6][MAX_TEXTURE_LEVELS];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment