Fix FBO/Texture/renderbuffer class hierarchy issues
TRAC #14744
Issue=51/52
Delegated format queries to RenderbufferStorage.
Eliminated TextureColorbufferProxy by merging it into Colorbuffer.
Abstracted texture colorbuffer queries.
Moved some conversion functions to the right namespace.
Fixed line-endings in Texture.cpp
Signed-off-by: Daniel Koch
Author: Nicolas Capens <nicolas@transgaming.com>
git-svn-id: https://angleproject.googlecode.com/svn/trunk@553 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index bfa4d2a..d3c4ff7 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -2378,7 +2378,7 @@
D3DSURFACE_DESC desc;
depthStencil->GetDesc(&desc);
- unsigned int stencilSize = es2dx::GetStencilSize(desc.Format);
+ unsigned int stencilSize = dx2es::GetStencilSize(desc.Format);
stencilUnmasked = (0x1 << stencilSize) - 1;
if (stencilUnmasked != 0x0)
@@ -2415,7 +2415,7 @@
D3DSURFACE_DESC desc;
renderTarget->GetDesc(&desc);
- bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || mState.colorMaskAlpha;
+ bool alphaUnmasked = (dx2es::GetAlphaSize(desc.Format) == 0) || mState.colorMaskAlpha;
const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) &&
(mState.stencilWritemask & stencilUnmasked) != stencilUnmasked;
diff --git a/src/libGLESv2/Framebuffer.cpp b/src/libGLESv2/Framebuffer.cpp
index 5fe01e0..dd34725 100644
--- a/src/libGLESv2/Framebuffer.cpp
+++ b/src/libGLESv2/Framebuffer.cpp
@@ -46,7 +46,7 @@
}
else if (IsTextureTarget(type))
{
- buffer = context->getTexture(handle)->getColorbuffer(type);
+ buffer = context->getTexture(handle)->getRenderbuffer(type);
}
else
{
@@ -307,14 +307,14 @@
if (mColorbufferType == GL_RENDERBUFFER)
{
- if (!gl::IsColorRenderable(colorbuffer->getFormat()))
+ if (!gl::IsColorRenderable(colorbuffer->getInternalFormat()))
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
}
else if (IsTextureTarget(mColorbufferType))
{
- if (IsCompressed(colorbuffer->getFormat()))
+ if (IsCompressed(colorbuffer->getInternalFormat()))
{
return GL_FRAMEBUFFER_UNSUPPORTED;
}
@@ -325,7 +325,7 @@
return GL_FRAMEBUFFER_UNSUPPORTED;
}
- if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA)
+ if (colorbuffer->getInternalFormat() == GL_LUMINANCE || colorbuffer->getInternalFormat() == GL_LUMINANCE_ALPHA)
{
return GL_FRAMEBUFFER_UNSUPPORTED;
}
@@ -424,8 +424,8 @@
if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
{
- if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
- stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
+ if (depthbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES ||
+ stencilbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES ||
depthbuffer->getSerial() != stencilbuffer->getSerial())
{
return GL_FRAMEBUFFER_UNSUPPORTED;
diff --git a/src/libGLESv2/Renderbuffer.cpp b/src/libGLESv2/Renderbuffer.cpp
index 6e4494b..7597504 100644
--- a/src/libGLESv2/Renderbuffer.cpp
+++ b/src/libGLESv2/Renderbuffer.cpp
@@ -54,24 +54,54 @@
return mStorage->getDepthStencil();
}
-int Renderbuffer::getWidth() const
+GLsizei Renderbuffer::getWidth() const
{
return mStorage->getWidth();
}
-int Renderbuffer::getHeight() const
+GLsizei Renderbuffer::getHeight() const
{
return mStorage->getHeight();
}
-GLenum Renderbuffer::getFormat() const
+GLenum Renderbuffer::getInternalFormat() const
{
- return mStorage->getFormat();
+ return mStorage->getInternalFormat();
}
-D3DFORMAT Renderbuffer::getD3DFormat() const
+GLuint Renderbuffer::getRedSize() const
{
- return mStorage->getD3DFormat();
+ return mStorage->getRedSize();
+}
+
+GLuint Renderbuffer::getGreenSize() const
+{
+ return mStorage->getGreenSize();
+}
+
+GLuint Renderbuffer::getBlueSize() const
+{
+ return mStorage->getBlueSize();
+}
+
+GLuint Renderbuffer::getAlphaSize() const
+{
+ return mStorage->getAlphaSize();
+}
+
+GLuint Renderbuffer::getDepthSize() const
+{
+ return mStorage->getDepthSize();
+}
+
+GLuint Renderbuffer::getStencilSize() const
+{
+ return mStorage->getStencilSize();
+}
+
+GLsizei Renderbuffer::getSamples() const
+{
+ return mStorage->getSamples();
}
unsigned int Renderbuffer::getSerial() const
@@ -91,7 +121,7 @@
{
mWidth = 0;
mHeight = 0;
- mFormat = GL_RGBA4;
+ mInternalFormat = GL_RGBA4;
mD3DFormat = D3DFMT_A8R8G8B8;
mSamples = 0;
}
@@ -125,35 +155,49 @@
return NULL;
}
-int RenderbufferStorage::getWidth() const
+GLsizei RenderbufferStorage::getWidth() const
{
return mWidth;
}
-int RenderbufferStorage::getHeight() const
+GLsizei RenderbufferStorage::getHeight() const
{
return mHeight;
}
-void RenderbufferStorage::setSize(int width, int height)
+GLenum RenderbufferStorage::getInternalFormat() const
{
- mWidth = width;
- mHeight = height;
+ return mInternalFormat;
}
-GLenum RenderbufferStorage::getFormat() const
+GLuint RenderbufferStorage::getRedSize() const
{
- return mFormat;
+ return dx2es::GetRedSize(getD3DFormat());
}
-bool RenderbufferStorage::isFloatingPoint() const
+GLuint RenderbufferStorage::getGreenSize() const
{
- return false; // no floating point renderbuffers
+ return dx2es::GetGreenSize(getD3DFormat());
}
-D3DFORMAT RenderbufferStorage::getD3DFormat() const
+GLuint RenderbufferStorage::getBlueSize() const
{
- return mD3DFormat;
+ return dx2es::GetBlueSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getAlphaSize() const
+{
+ return dx2es::GetAlphaSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getDepthSize() const
+{
+ return dx2es::GetDepthSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getStencilSize() const
+{
+ return dx2es::GetStencilSize(getD3DFormat());
}
GLsizei RenderbufferStorage::getSamples() const
@@ -161,6 +205,11 @@
return mSamples;
}
+D3DFORMAT RenderbufferStorage::getD3DFormat() const
+{
+ return mD3DFormat;
+}
+
unsigned int RenderbufferStorage::getSerial() const
{
return mSerial;
@@ -171,7 +220,7 @@
return mCurrentSerial++;
}
-Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget)
+Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget), mTexture(NULL)
{
if (renderTarget)
{
@@ -180,25 +229,32 @@
D3DSURFACE_DESC description;
renderTarget->GetDesc(&description);
- setSize(description.Width, description.Height);
- mFormat = dx2es::ConvertBackBufferFormat(description.Format);
+ mWidth = description.Width;
+ mHeight = description.Height;
+ mInternalFormat = dx2es::ConvertBackBufferFormat(description.Format);
mD3DFormat = description.Format;
- mSamples = es2dx::GetSamplesFromMultisampleType(description.MultiSampleType);
+ mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType);
}
}
-Colorbuffer::Colorbuffer(const Texture* texture) : mRenderTarget(NULL)
+Colorbuffer::Colorbuffer(Texture *texture, GLenum target) : mRenderTarget(NULL), mTexture(texture), mTarget(target)
{
- setSize(texture->getWidth(), texture->getHeight());
- mD3DFormat = texture->getD3DFormat();
- mSamples = 0;
+ if (texture)
+ {
+ mWidth = texture->getWidth();
+ mHeight = texture->getHeight();
+ mInternalFormat = texture->getInternalFormat();
+ mD3DFormat = texture->getD3DFormat();
+ mSamples = 0;
+
+ mRenderTarget = texture->getRenderTarget(target);
+ }
}
-Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples)
+Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL), mTexture(NULL)
{
IDirect3DDevice9 *device = getDevice();
- mRenderTarget = NULL;
D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format);
int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples);
@@ -226,8 +282,9 @@
if (mRenderTarget)
{
- setSize(width, height);
- mFormat = format;
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = format;
mD3DFormat = requestedFormat;
mSamples = supportedSamples;
}
@@ -241,65 +298,73 @@
}
}
+GLsizei Colorbuffer::getWidth() const
+{
+ if (mTexture)
+ {
+ return mTexture->getWidth();
+ }
+
+ return mWidth;
+}
+
+GLsizei Colorbuffer::getHeight() const
+{
+ if (mTexture)
+ {
+ return mTexture->getHeight();
+ }
+
+ return mHeight;
+}
+
+GLenum Colorbuffer::getInternalFormat() const
+{
+ if (mTexture)
+ {
+ return mTexture->getInternalFormat();
+ }
+
+ return mInternalFormat;
+}
+
+D3DFORMAT Colorbuffer::getD3DFormat() const
+{
+ if (mTexture)
+ {
+ return mTexture->getD3DFormat();
+ }
+
+ return mD3DFormat;
+}
+
+bool Colorbuffer::isFloatingPoint() const
+{
+ if (mTexture)
+ {
+ return mTexture->isFloatingPoint();
+ }
+
+ return false;
+}
+
bool Colorbuffer::isColorbuffer() const
{
return true;
}
-GLuint Colorbuffer::getRedSize() const
-{
- if (mRenderTarget)
- {
- D3DSURFACE_DESC description;
- mRenderTarget->GetDesc(&description);
-
- return es2dx::GetRedSize(description.Format);
- }
-
- return 0;
-}
-
-GLuint Colorbuffer::getGreenSize() const
-{
- if (mRenderTarget)
- {
- D3DSURFACE_DESC description;
- mRenderTarget->GetDesc(&description);
-
- return es2dx::GetGreenSize(description.Format);
- }
-
- return 0;
-}
-
-GLuint Colorbuffer::getBlueSize() const
-{
- if (mRenderTarget)
- {
- D3DSURFACE_DESC description;
- mRenderTarget->GetDesc(&description);
-
- return es2dx::GetBlueSize(description.Format);
- }
-
- return 0;
-}
-
-GLuint Colorbuffer::getAlphaSize() const
-{
- if (mRenderTarget)
- {
- D3DSURFACE_DESC description;
- mRenderTarget->GetDesc(&description);
-
- return es2dx::GetAlphaSize(description.Format);
- }
-
- return 0;
-}
-
IDirect3DSurface9 *Colorbuffer::getRenderTarget()
{
+ if (mTexture)
+ {
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ }
+
+ mRenderTarget = mTexture->getRenderTarget(mTarget);
+ }
+
return mRenderTarget;
}
@@ -312,9 +377,10 @@
D3DSURFACE_DESC description;
depthStencil->GetDesc(&description);
- setSize(description.Width, description.Height);
- mFormat = dx2es::ConvertDepthStencilFormat(description.Format);
- mSamples = es2dx::GetSamplesFromMultisampleType(description.MultiSampleType);
+ mWidth = description.Width;
+ mHeight = description.Height;
+ mInternalFormat = dx2es::ConvertDepthStencilFormat(description.Format);
+ mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType);
mD3DFormat = description.Format;
}
}
@@ -348,8 +414,9 @@
if (mDepthStencil)
{
- setSize(width, height);
- mFormat = GL_DEPTH24_STENCIL8_OES;
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = GL_DEPTH24_STENCIL8_OES;
mD3DFormat = D3DFMT_D24S8;
mSamples = supportedSamples;
}
@@ -373,32 +440,6 @@
return true;
}
-GLuint DepthStencilbuffer::getDepthSize() const
-{
- if (mDepthStencil)
- {
- D3DSURFACE_DESC description;
- mDepthStencil->GetDesc(&description);
-
- return es2dx::GetDepthSize(description.Format);
- }
-
- return 0;
-}
-
-GLuint DepthStencilbuffer::getStencilSize() const
-{
- if (mDepthStencil)
- {
- D3DSURFACE_DESC description;
- mDepthStencil->GetDesc(&description);
-
- return es2dx::GetStencilSize(description.Format);
- }
-
- return 0;
-}
-
IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil()
{
return mDepthStencil;
@@ -408,9 +449,9 @@
{
if (depthStencil)
{
- mFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
- // will expect one of the valid renderbuffer formats for use in
- // glRenderbufferStorage
+ mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
}
}
@@ -418,9 +459,9 @@
{
if (getDepthStencil())
{
- mFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
- // will expect one of the valid renderbuffer formats for use in
- // glRenderbufferStorage
+ mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
}
}
@@ -442,13 +483,9 @@
{
if (depthStencil)
{
- mFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
- // will expect one of the valid renderbuffer formats for use in
- // glRenderbufferStorage
- }
- else
- {
- mFormat = GL_RGBA4; //default format
+ mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
}
}
@@ -456,9 +493,9 @@
{
if (getDepthStencil())
{
- mFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
- // will expect one of the valid renderbuffer formats for use in
- // glRenderbufferStorage
+ mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
}
}
diff --git a/src/libGLESv2/Renderbuffer.h b/src/libGLESv2/Renderbuffer.h
index 98510c2..d6415bb 100644
--- a/src/libGLESv2/Renderbuffer.h
+++ b/src/libGLESv2/Renderbuffer.h
@@ -21,7 +21,7 @@
namespace gl
{
- class Texture;
+class Texture;
// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage
// is called. The specific concrete type depends on whether the internal format is
@@ -40,34 +40,40 @@
virtual IDirect3DSurface9 *getRenderTarget();
virtual IDirect3DSurface9 *getDepthStencil();
- virtual int getWidth() const;
- virtual int getHeight() const;
- virtual GLenum getFormat() const;
- virtual bool isFloatingPoint() const;
- D3DFORMAT getD3DFormat() const;
- GLsizei getSamples() const;
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+ virtual GLsizei getSamples() const;
+
+ virtual D3DFORMAT getD3DFormat() const;
+
unsigned int getSerial() const;
- static unsigned int issueSerial();
-
protected:
- void setSize(int width, int height);
- GLenum mFormat;
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLenum mInternalFormat;
D3DFORMAT mD3DFormat;
GLsizei mSamples;
- const unsigned int mSerial;
private:
DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage);
- static unsigned int mCurrentSerial;
+ static unsigned int issueSerial();
- int mWidth;
- int mHeight;
+ const unsigned int mSerial;
+
+ static unsigned int mCurrentSerial;
};
// Renderbuffer implements the GL renderbuffer object.
-// It's only a wrapper for a RenderbufferStorage, but the internal object
+// It's only a proxy for a RenderbufferStorage instance; the internal object
// can change whenever glRenderbufferStorage is called.
class Renderbuffer : public RefCountObject
{
@@ -83,10 +89,18 @@
IDirect3DSurface9 *getRenderTarget();
IDirect3DSurface9 *getDepthStencil();
- int getWidth() const;
- int getHeight() const;
- GLenum getFormat() const;
+ GLsizei getWidth() const;
+ GLsizei getHeight() const;
+ GLenum getInternalFormat() const;
D3DFORMAT getD3DFormat() const;
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+ GLsizei getSamples() const;
+
unsigned int getSerial() const;
void setStorage(RenderbufferStorage *newStorage);
@@ -102,42 +116,43 @@
{
public:
explicit Colorbuffer(IDirect3DSurface9 *renderTarget);
- explicit Colorbuffer(const Texture* texture);
- Colorbuffer(int width, int height, GLenum format, GLsizei samples);
+ Colorbuffer(Texture *texture, GLenum target);
+ Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
- ~Colorbuffer();
+ virtual ~Colorbuffer();
- bool isColorbuffer() const;
+ virtual bool isColorbuffer() const;
- GLuint getRedSize() const;
- GLuint getGreenSize() const;
- GLuint getBlueSize() const;
- GLuint getAlphaSize() const;
+ virtual IDirect3DSurface9 *getRenderTarget();
- IDirect3DSurface9 *getRenderTarget();
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
- protected:
- IDirect3DSurface9 *mRenderTarget;
+ virtual D3DFORMAT getD3DFormat() const;
+
+ bool isFloatingPoint() const;
private:
DISALLOW_COPY_AND_ASSIGN(Colorbuffer);
+
+ IDirect3DSurface9 *mRenderTarget;
+ Texture *mTexture;
+ GLenum mTarget;
};
class DepthStencilbuffer : public RenderbufferStorage
{
public:
explicit DepthStencilbuffer(IDirect3DSurface9 *depthStencil);
- DepthStencilbuffer(int width, int height, GLsizei samples);
+ DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
~DepthStencilbuffer();
virtual bool isDepthbuffer() const;
virtual bool isStencilbuffer() const;
- GLuint getDepthSize() const;
- GLuint getStencilSize() const;
-
- IDirect3DSurface9 *getDepthStencil();
+ virtual IDirect3DSurface9 *getDepthStencil();
private:
DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer);
@@ -148,12 +163,12 @@
{
public:
explicit Depthbuffer(IDirect3DSurface9 *depthStencil);
- Depthbuffer(int width, int height, GLsizei samples);
+ Depthbuffer(GLsizei width, GLsizei height, GLsizei samples);
- ~Depthbuffer();
+ virtual ~Depthbuffer();
- bool isDepthbuffer() const;
- bool isStencilbuffer() const;
+ virtual bool isDepthbuffer() const;
+ virtual bool isStencilbuffer() const;
private:
DISALLOW_COPY_AND_ASSIGN(Depthbuffer);
@@ -163,12 +178,12 @@
{
public:
explicit Stencilbuffer(IDirect3DSurface9 *depthStencil);
- Stencilbuffer(int width, int height, GLsizei samples);
+ Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
- ~Stencilbuffer();
+ virtual ~Stencilbuffer();
- bool isDepthbuffer() const;
- bool isStencilbuffer() const;
+ virtual bool isDepthbuffer() const;
+ virtual bool isStencilbuffer() const;
private:
DISALLOW_COPY_AND_ASSIGN(Stencilbuffer);
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 7a6ae8a..a0f446e 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -1,2509 +1,2464 @@
-//
-// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// Texture.cpp: Implements the gl::Texture class and its derived classes
-// Texture2D and TextureCubeMap. Implements GL texture objects and related
-// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
-
-#include "libGLESv2/Texture.h"
-
-#include <d3dx9tex.h>
-
-#include <algorithm>
-
-#include "common/debug.h"
-
-#include "libGLESv2/main.h"
-#include "libGLESv2/mathutil.h"
-#include "libGLESv2/utilities.h"
-#include "libGLESv2/Blit.h"
-#include "libGLESv2/Framebuffer.h"
-
-namespace gl
-{
-
-Texture::Image::Image()
- : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
-{
-}
-
-Texture::Image::~Image()
-{
- if (surface) surface->Release();
-}
-
-Texture::Texture(GLuint id) : RefCountObject(id)
-{
- mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
- mMagFilter = GL_LINEAR;
- mWrapS = GL_REPEAT;
- mWrapT = GL_REPEAT;
-
- mWidth = 0;
- mHeight = 0;
-
- mDirtyMetaData = true;
- mDirty = true;
- mIsRenderable = false;
- mType = GL_UNSIGNED_BYTE;
- mBaseTexture = NULL;
-}
-
-Texture::~Texture()
-{
-}
-
-Blit *Texture::getBlitter()
-{
- Context *context = getContext();
- return context->getBlitter();
-}
-
-// Returns true on successful filter state update (valid enum parameter)
-bool Texture::setMinFilter(GLenum filter)
-{
- switch (filter)
- {
- case GL_NEAREST:
- case GL_LINEAR:
- case GL_NEAREST_MIPMAP_NEAREST:
- case GL_LINEAR_MIPMAP_NEAREST:
- case GL_NEAREST_MIPMAP_LINEAR:
- case GL_LINEAR_MIPMAP_LINEAR:
- {
- if (mMinFilter != filter)
- {
- mMinFilter = filter;
- mDirty = true;
- }
- return true;
- }
- default:
- return false;
- }
-}
-
-// Returns true on successful filter state update (valid enum parameter)
-bool Texture::setMagFilter(GLenum filter)
-{
- switch (filter)
- {
- case GL_NEAREST:
- case GL_LINEAR:
- {
- if (mMagFilter != filter)
- {
- mMagFilter = filter;
- mDirty = true;
- }
- return true;
- }
- default:
- return false;
- }
-}
-
-// Returns true on successful wrap state update (valid enum parameter)
-bool Texture::setWrapS(GLenum wrap)
-{
- switch (wrap)
- {
- case GL_REPEAT:
- case GL_CLAMP_TO_EDGE:
- case GL_MIRRORED_REPEAT:
- {
- if (mWrapS != wrap)
- {
- mWrapS = wrap;
- mDirty = true;
- }
- return true;
- }
- default:
- return false;
- }
-}
-
-// Returns true on successful wrap state update (valid enum parameter)
-bool Texture::setWrapT(GLenum wrap)
-{
- switch (wrap)
- {
- case GL_REPEAT:
- case GL_CLAMP_TO_EDGE:
- case GL_MIRRORED_REPEAT:
- {
- if (mWrapT != wrap)
- {
- mWrapT = wrap;
- mDirty = true;
- }
- return true;
- }
- default:
- return false;
- }
-}
-
-GLenum Texture::getMinFilter() const
-{
- return mMinFilter;
-}
-
-GLenum Texture::getMagFilter() const
-{
- return mMagFilter;
-}
-
-GLenum Texture::getWrapS() const
-{
- return mWrapS;
-}
-
-GLenum Texture::getWrapT() const
-{
- return mWrapT;
-}
-
-GLuint Texture::getWidth() const
-{
- return mWidth;
-}
-
-GLuint Texture::getHeight() const
-{
- return mHeight;
-}
-
-bool Texture::isFloatingPoint() const
-{
- return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
-}
-
-bool Texture::isRenderableFormat() const
-{
- D3DFORMAT format = getD3DFormat();
-
- switch(format)
- {
- case D3DFMT_L8:
- case D3DFMT_A8L8:
- case D3DFMT_DXT1:
- return false;
- case D3DFMT_A8R8G8B8:
- case D3DFMT_X8R8G8B8:
- case D3DFMT_A16B16G16R16F:
- case D3DFMT_A32B32G32R32F:
- return true;
- default:
- UNREACHABLE();
- }
-
- return false;
-}
-
-// Selects an internal Direct3D 9 format for storing an Image
-D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
-{
- if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
- format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
- {
- return D3DFMT_DXT1;
- }
- else if (type == GL_FLOAT)
- {
- return D3DFMT_A32B32G32R32F;
- }
- else if (type == GL_HALF_FLOAT_OES)
- {
- return D3DFMT_A16B16G16R16F;
- }
- else if (type == GL_UNSIGNED_BYTE)
- {
- if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
- {
- return D3DFMT_L8;
- }
- else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
- {
- return D3DFMT_A8L8;
- }
- else if (format == GL_RGB)
- {
- return D3DFMT_X8R8G8B8;
- }
-
- return D3DFMT_A8R8G8B8;
- }
-
- return D3DFMT_A8R8G8B8;
-}
-
-// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
-// into the target pixel rectangle at output with outputPitch bytes in between each line.
-void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
- GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
-{
- GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
- input = ((char*)input) - inputPitch * (height - 1);
-
- switch (type)
- {
- case GL_UNSIGNED_BYTE:
- switch (format)
- {
- case GL_ALPHA:
- loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_LUMINANCE:
- loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
- break;
- case GL_LUMINANCE_ALPHA:
- loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
- break;
- case GL_RGB:
- loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_RGBA:
- loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_BGRA_EXT:
- loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- default: UNREACHABLE();
- }
- break;
- case GL_UNSIGNED_SHORT_5_6_5:
- switch (format)
- {
- case GL_RGB:
- loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- default: UNREACHABLE();
- }
- break;
- case GL_UNSIGNED_SHORT_4_4_4_4:
- switch (format)
- {
- case GL_RGBA:
- loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- default: UNREACHABLE();
- }
- break;
- case GL_UNSIGNED_SHORT_5_5_5_1:
- switch (format)
- {
- case GL_RGBA:
- loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- default: UNREACHABLE();
- }
- break;
- case GL_FLOAT:
- switch (format)
- {
- // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
- case GL_ALPHA:
- loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_LUMINANCE:
- loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_LUMINANCE_ALPHA:
- loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_RGB:
- loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_RGBA:
- loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- default: UNREACHABLE();
- }
- break;
- case GL_HALF_FLOAT_OES:
- switch (format)
- {
- // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
- case GL_ALPHA:
- loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_LUMINANCE:
- loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_LUMINANCE_ALPHA:
- loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_RGB:
- loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- case GL_RGBA:
- loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
- break;
- default: UNREACHABLE();
- }
- break;
- default: UNREACHABLE();
- }
-}
-
-void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = 0;
- dest[4 * x + 1] = 0;
- dest[4 * x + 2] = 0;
- dest[4 * x + 3] = source[x];
- }
- }
-}
-
-void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const float *source = NULL;
- float *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = 0;
- dest[4 * x + 1] = 0;
- dest[4 * x + 2] = 0;
- dest[4 * x + 3] = source[x];
- }
- }
-}
-
-void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned short *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = 0;
- dest[4 * x + 1] = 0;
- dest[4 * x + 2] = 0;
- dest[4 * x + 3] = source[x];
- }
- }
-}
-
-void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
-{
- const int destBytesPerPixel = native? 1: 4;
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
-
- if (!native) // BGRA8 destination format
- {
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x];
- dest[4 * x + 1] = source[x];
- dest[4 * x + 2] = source[x];
- dest[4 * x + 3] = 0xFF;
- }
- }
- else // L8 destination format
- {
- memcpy(dest, source, width);
- }
- }
-}
-
-void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const float *source = NULL;
- float *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x];
- dest[4 * x + 1] = source[x];
- dest[4 * x + 2] = source[x];
- dest[4 * x + 3] = 1.0f;
- }
- }
-}
-
-void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned short *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x];
- dest[4 * x + 1] = source[x];
- dest[4 * x + 2] = source[x];
- dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
- }
- }
-}
-
-void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
-{
- const int destBytesPerPixel = native? 2: 4;
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
-
- if (!native) // BGRA8 destination format
- {
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[2*x+0];
- dest[4 * x + 1] = source[2*x+0];
- dest[4 * x + 2] = source[2*x+0];
- dest[4 * x + 3] = source[2*x+1];
- }
- }
- else
- {
- memcpy(dest, source, width * 2);
- }
- }
-}
-
-void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const float *source = NULL;
- float *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[2*x+0];
- dest[4 * x + 1] = source[2*x+0];
- dest[4 * x + 2] = source[2*x+0];
- dest[4 * x + 3] = source[2*x+1];
- }
- }
-}
-
-void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned short *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[2*x+0];
- dest[4 * x + 1] = source[2*x+0];
- dest[4 * x + 2] = source[2*x+0];
- dest[4 * x + 3] = source[2*x+1];
- }
- }
-}
-
-void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x * 3 + 2];
- dest[4 * x + 1] = source[x * 3 + 1];
- dest[4 * x + 2] = source[x * 3 + 0];
- dest[4 * x + 3] = 0xFF;
- }
- }
-}
-
-void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- for (int x = 0; x < width; x++)
- {
- unsigned short rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
- dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
- dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
- dest[4 * x + 3] = 0xFF;
- }
- }
-}
-
-void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const float *source = NULL;
- float *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x * 3 + 0];
- dest[4 * x + 1] = source[x * 3 + 1];
- dest[4 * x + 2] = source[x * 3 + 2];
- dest[4 * x + 3] = 1.0f;
- }
- }
-}
-
-void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned short *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x * 3 + 0];
- dest[4 * x + 1] = source[x * 3 + 1];
- dest[4 * x + 2] = source[x * 3 + 2];
- dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
- }
- }
-}
-
-void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- for (int x = 0; x < width; x++)
- {
- dest[4 * x + 0] = source[x * 4 + 2];
- dest[4 * x + 1] = source[x * 4 + 1];
- dest[4 * x + 2] = source[x * 4 + 0];
- dest[4 * x + 3] = source[x * 4 + 3];
- }
- }
-}
-
-void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- for (int x = 0; x < width; x++)
- {
- unsigned short rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
- dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
- dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
- dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
- }
- }
-}
-
-void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned short *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- for (int x = 0; x < width; x++)
- {
- unsigned short rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
- dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
- dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
- dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
- }
- }
-}
-
-void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const float *source = NULL;
- float *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
- memcpy(dest, source, width * 16);
- }
-}
-
-void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
- memcpy(dest, source, width * 8);
- }
-}
-
-void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- const unsigned char *source = NULL;
- unsigned char *dest = NULL;
-
- for (int y = 0; y < height; y++)
- {
- source = static_cast<const unsigned char*>(input) + y * inputPitch;
- dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
- memcpy(dest, source, width*4);
- }
-}
-
-void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
- ASSERT(xoffset % 4 == 0);
- ASSERT(yoffset % 4 == 0);
- ASSERT(width % 4 == 0 || width == 2 || width == 1);
- ASSERT(inputPitch % 8 == 0);
- ASSERT(outputPitch % 8 == 0);
-
- const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
- unsigned int *dest = reinterpret_cast<unsigned int*>(output);
-
- switch (height)
- {
- case 1:
- // Round width up in case it is 1.
- for (int x = 0; x < (width + 1) / 2; x += 2)
- {
- // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
- dest[x] = source[x];
-
- // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
- dest[x + 1] = source[x + 1];
- }
- break;
- case 2:
- // Round width up in case it is 1.
- for (int x = 0; x < (width + 1) / 2; x += 2)
- {
- // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
- dest[x] = source[x];
-
- // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
- dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
- ((source[x + 1] >> 8) & 0x000000FF);
- }
- break;
- default:
- ASSERT(height % 4 == 0);
- for (int y = 0; y < height / 4; ++y)
- {
- const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
- unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
-
- // Round width up in case it is 1.
- for (int x = 0; x < (width + 1) / 2; x += 2)
- {
- // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
- dest[x] = source[x];
-
- // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
- dest[x + 1] = (source[x + 1] >> 24) |
- ((source[x + 1] << 8) & 0x00FF0000) |
- ((source[x + 1] >> 8) & 0x0000FF00) |
- (source[x + 1] << 24);
- }
- }
- break;
- }
-}
-
-void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
-{
- IDirect3DTexture9 *newTexture = NULL;
- IDirect3DSurface9 *newSurface = NULL;
-
- if (width != 0 && height != 0)
- {
- int levelToFetch = 0;
- GLsizei requestWidth = width;
- GLsizei requestHeight = height;
- if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
- {
- bool isMult4 = false;
- int upsampleCount = 0;
- while (!isMult4)
- {
- requestWidth <<= 1;
- requestHeight <<= 1;
- upsampleCount++;
- if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
- {
- isMult4 = true;
- }
- }
- levelToFetch = upsampleCount;
- }
-
- HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
- D3DPOOL_SYSTEMMEM, &newTexture, NULL);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
- return error(GL_OUT_OF_MEMORY);
- }
-
- newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
- newTexture->Release();
- }
-
- if (img->surface) img->surface->Release();
- img->surface = newSurface;
-
- img->width = width;
- img->height = height;
- img->format = format;
-}
-
-void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
-{
- createSurface(width, height, format, type, img);
-
- if (pixels != NULL && img->surface != NULL)
- {
- D3DSURFACE_DESC description;
- img->surface->GetDesc(&description);
-
- D3DLOCKED_RECT locked;
- HRESULT result = img->surface->LockRect(&locked, NULL, 0);
-
- ASSERT(SUCCEEDED(result));
-
- if (SUCCEEDED(result))
- {
- loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
- img->surface->UnlockRect();
- }
-
- img->dirty = true;
- }
-
- mDirtyMetaData = true;
-}
-
-void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
-{
- createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
-
- if (pixels != NULL && img->surface != NULL)
- {
- D3DLOCKED_RECT locked;
- HRESULT result = img->surface->LockRect(&locked, NULL, 0);
-
- ASSERT(SUCCEEDED(result));
-
- if (SUCCEEDED(result))
- {
- int inputPitch = ComputeCompressedPitch(width, format);
- int inputSize = ComputeCompressedSize(width, height, format);
- loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
- img->surface->UnlockRect();
- }
-
- img->dirty = true;
- }
-
- mDirtyMetaData = true;
-}
-
-bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
-{
- if (width + xoffset > img->width || height + yoffset > img->height)
- {
- error(GL_INVALID_VALUE);
- return false;
- }
-
- if (!img->surface)
- {
- createSurface(img->width, img->height, format, type, img);
- }
-
- if (pixels != NULL && img->surface != NULL)
- {
- D3DSURFACE_DESC description;
- img->surface->GetDesc(&description);
-
- D3DLOCKED_RECT locked;
- HRESULT result = img->surface->LockRect(&locked, NULL, 0);
-
- ASSERT(SUCCEEDED(result));
-
- if (SUCCEEDED(result))
- {
- loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
- img->surface->UnlockRect();
- }
-
- img->dirty = true;
- }
-
- return true;
-}
-
-bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
-{
- if (width + xoffset > img->width || height + yoffset > img->height)
- {
- error(GL_INVALID_VALUE);
- return false;
- }
-
- if (format != getFormat())
- {
- error(GL_INVALID_OPERATION);
- return false;
- }
-
- if (!img->surface)
- {
- createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
- }
-
- if (pixels != NULL && img->surface != NULL)
- {
- RECT updateRegion;
- updateRegion.left = xoffset;
- updateRegion.right = xoffset + width;
- updateRegion.bottom = yoffset + height;
- updateRegion.top = yoffset;
-
- D3DLOCKED_RECT locked;
- HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
-
- ASSERT(SUCCEEDED(result));
-
- if (SUCCEEDED(result))
- {
- int inputPitch = ComputeCompressedPitch(width, format);
- int inputSize = ComputeCompressedSize(width, height, format);
- loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
- img->surface->UnlockRect();
- }
-
- img->dirty = true;
- }
-
- return true;
-}
-
-// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
-void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
-{
- IDirect3DDevice9 *device = getDevice();
- IDirect3DSurface9 *surface = NULL;
- D3DSURFACE_DESC description;
- renderTarget->GetDesc(&description);
-
- HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
-
- if (!SUCCEEDED(result))
- {
- ERR("Could not create matching destination surface.");
- return error(GL_OUT_OF_MEMORY);
- }
-
- result = device->GetRenderTargetData(renderTarget, surface);
-
- if (!SUCCEEDED(result))
- {
- ERR("GetRenderTargetData unexpectedly failed.");
- surface->Release();
- return error(GL_OUT_OF_MEMORY);
- }
-
- D3DLOCKED_RECT sourceLock = {0};
- RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
- result = surface->LockRect(&sourceLock, &sourceRect, 0);
-
- if (FAILED(result))
- {
- ERR("Failed to lock the source surface (rectangle might be invalid).");
- surface->UnlockRect();
- surface->Release();
- return error(GL_OUT_OF_MEMORY);
- }
-
- if (!image->surface)
- {
- createSurface(width, height, internalFormat, mType, image);
- }
-
- if (image->surface == NULL)
- {
- ERR("Failed to create an image surface.");
- surface->UnlockRect();
- surface->Release();
- return error(GL_OUT_OF_MEMORY);
- }
-
- D3DLOCKED_RECT destLock = {0};
- int destYOffset = transformPixelYOffset(yoffset, height, image->height);
- RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
- result = image->surface->LockRect(&destLock, &destRect, 0);
-
- if (FAILED(result))
- {
- ERR("Failed to lock the destination surface (rectangle might be invalid).");
- surface->UnlockRect();
- surface->Release();
- return error(GL_OUT_OF_MEMORY);
- }
-
- if (destLock.pBits && sourceLock.pBits)
- {
- unsigned char *source = (unsigned char*)sourceLock.pBits;
- unsigned char *dest = (unsigned char*)destLock.pBits;
-
- switch (description.Format)
- {
- case D3DFMT_X8R8G8B8:
- case D3DFMT_A8R8G8B8:
- switch(getD3DFormat())
- {
- case D3DFMT_L8:
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
- {
- dest[x] = source[x * 4 + 2];
- }
-
- source += sourceLock.Pitch;
- dest += destLock.Pitch;
- }
- break;
- case D3DFMT_A8L8:
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
- {
- dest[x * 2 + 0] = source[x * 4 + 2];
- dest[x * 2 + 1] = source[x * 4 + 3];
- }
-
- source += sourceLock.Pitch;
- dest += destLock.Pitch;
- }
- break;
- default:
- UNREACHABLE();
- }
- break;
- case D3DFMT_R5G6B5:
- switch(getD3DFormat())
- {
- case D3DFMT_L8:
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
- {
- unsigned char red = source[x * 2 + 1] & 0xF8;
- dest[x] = red | (red >> 5);
- }
-
- source += sourceLock.Pitch;
- dest += destLock.Pitch;
- }
- break;
- default:
- UNREACHABLE();
- }
- break;
- case D3DFMT_A1R5G5B5:
- switch(getD3DFormat())
- {
- case D3DFMT_L8:
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
- {
- unsigned char red = source[x * 2 + 1] & 0x7C;
- dest[x] = (red << 1) | (red >> 4);
- }
-
- source += sourceLock.Pitch;
- dest += destLock.Pitch;
- }
- break;
- case D3DFMT_A8L8:
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
- {
- unsigned char red = source[x * 2 + 1] & 0x7C;
- dest[x * 2 + 0] = (red << 1) | (red >> 4);
- dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
- }
-
- source += sourceLock.Pitch;
- dest += destLock.Pitch;
- }
- break;
- default:
- UNREACHABLE();
- }
- break;
- default:
- UNREACHABLE();
- }
-
- image->dirty = true;
- mDirtyMetaData = true;
- }
-
- image->surface->UnlockRect();
- surface->UnlockRect();
- surface->Release();
-}
-
-D3DFORMAT Texture::getD3DFormat() const
-{
- return selectFormat(getFormat(), mType);
-}
-
-IDirect3DBaseTexture9 *Texture::getTexture()
-{
- if (!isComplete())
- {
- return NULL;
- }
-
- if (mDirtyMetaData)
- {
- mBaseTexture = createTexture();
- mIsRenderable = false;
- }
-
- if (mDirtyMetaData || dirtyImageData())
- {
- updateTexture();
- }
-
- mDirtyMetaData = false;
- ASSERT(!dirtyImageData());
-
- return mBaseTexture;
-}
-
-bool Texture::isDirty() const
-{
- return (mDirty || mDirtyMetaData || dirtyImageData());
-}
-
-// Returns the top-level texture surface as a render target
-void Texture::needRenderTarget()
-{
- if (!mIsRenderable)
- {
- mBaseTexture = convertToRenderTarget();
- mIsRenderable = true;
- }
-
- if (dirtyImageData())
- {
- updateTexture();
- }
-
- mDirtyMetaData = false;
-}
-
-void Texture::dropTexture()
-{
- if (mBaseTexture)
- {
- mBaseTexture = NULL;
- }
-
- mIsRenderable = false;
-}
-
-void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
-{
- mBaseTexture = newTexture;
- mDirtyMetaData = false;
- mIsRenderable = renderable;
- mDirty = true;
-}
-
-
-GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
-{
- if (isPow2(width) && isPow2(height))
- {
- return maxlevel;
- }
- else
- {
- // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
- return 1;
- }
-}
-
-GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
-{
- return creationLevels(size, size, maxlevel);
-}
-
-int Texture::levelCount() const
-{
- return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
-}
-
-bool Texture::isRenderable() const
-{
- return mIsRenderable;
-}
-
-Texture2D::Texture2D(GLuint id) : Texture(id)
-{
- mTexture = NULL;
-}
-
-Texture2D::~Texture2D()
-{
- mColorbufferProxy.set(NULL);
-
- if (mTexture)
- {
- mTexture->Release();
- mTexture = NULL;
- }
-}
-
-GLenum Texture2D::getTarget() const
-{
- return GL_TEXTURE_2D;
-}
-
-GLenum Texture2D::getFormat() const
-{
- return mImageArray[0].format;
-}
-
-// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
-// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
-// Call this when a particular level of the texture must be defined with a specific format, width and height.
-//
-// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
-// a new height and width for the texture by working backwards from the given width and height.
-bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
-{
- bool widthOkay = (mWidth >> level == width);
- bool heightOkay = (mHeight >> level == height);
-
- bool sizeOkay = ((widthOkay && heightOkay)
- || (widthOkay && mHeight >> level == 0 && height == 1)
- || (heightOkay && mWidth >> level == 0 && width == 1));
-
- bool typeOkay = (type == mType);
-
- bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
-
- if (!textureOkay)
- {
- TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
- mImageArray[0].format, mWidth, mHeight,
- internalFormat, width, height);
-
- // Purge all the levels and the texture.
-
- for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- if (mImageArray[i].surface != NULL)
- {
- mImageArray[i].dirty = false;
-
- mImageArray[i].surface->Release();
- mImageArray[i].surface = NULL;
- }
- }
-
- if (mTexture != NULL)
- {
- mTexture->Release();
- mTexture = NULL;
- dropTexture();
- }
-
- mWidth = width << level;
- mHeight = height << level;
- mImageArray[0].format = internalFormat;
- mType = type;
- }
-
- return !textureOkay;
-}
-
-void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- redefineTexture(level, internalFormat, width, height, type);
-
- Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
-}
-
-void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
-{
- redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
-
- Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
-}
-
-void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
-{
- ASSERT(mImageArray[level].surface != NULL);
-
- if (level < levelCount())
- {
- IDirect3DSurface9 *destLevel = NULL;
- HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
-
- ASSERT(SUCCEEDED(result));
-
- if (SUCCEEDED(result))
- {
- Image *img = &mImageArray[level];
-
- RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
-
- POINT destPoint;
- destPoint.x = sourceRect.left;
- destPoint.y = sourceRect.top;
-
- result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
- ASSERT(SUCCEEDED(result));
-
- destLevel->Release();
-
- img->dirty = false;
- }
- }
-}
-
-void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
- {
- commitRect(level, xoffset, yoffset, width, height);
- }
-}
-
-void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
-{
- if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
- {
- commitRect(level, xoffset, yoffset, width, height);
- }
-}
-
-void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
- IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
- if (!renderTarget)
- {
- ERR("Failed to retrieve the render target.");
- return error(GL_OUT_OF_MEMORY);
- }
-
- bool redefined = redefineTexture(level, internalFormat, width, height, mType);
-
- if (!isRenderableFormat())
- {
- copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
- }
- else
- {
- if (redefined)
- {
- convertToRenderTarget();
- pushTexture(mTexture, true);
- }
- else
- {
- needRenderTarget();
- }
-
- if (width != 0 && height != 0 && level < levelCount())
- {
- RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
- sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
- sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
- sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
- sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
- IDirect3DSurface9 *dest;
- HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
-
- getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
- dest->Release();
- }
- }
-
- mImageArray[level].width = width;
- mImageArray[level].height = height;
- mImageArray[level].format = internalFormat;
-}
-
-void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
- if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
- {
- return error(GL_INVALID_VALUE);
- }
-
- IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
- if (!renderTarget)
- {
- ERR("Failed to retrieve the render target.");
- return error(GL_OUT_OF_MEMORY);
- }
-
- bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
-
- if (!isRenderableFormat())
- {
- copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
- }
- else
- {
- if (redefined)
- {
- convertToRenderTarget();
- pushTexture(mTexture, true);
- }
- else
- {
- needRenderTarget();
- }
-
- if (level < levelCount())
- {
- RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
- sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
- sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
- sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
- sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
- GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
-
- IDirect3DSurface9 *dest;
- HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
-
- getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
- dest->Release();
- }
- }
-}
-
-// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
-bool Texture2D::isComplete() const
-{
- GLsizei width = mImageArray[0].width;
- GLsizei height = mImageArray[0].height;
-
- if (width <= 0 || height <= 0)
- {
- return false;
- }
-
- bool mipmapping = false;
-
- switch (mMinFilter)
- {
- case GL_NEAREST:
- case GL_LINEAR:
- mipmapping = false;
- break;
- case GL_NEAREST_MIPMAP_NEAREST:
- case GL_LINEAR_MIPMAP_NEAREST:
- case GL_NEAREST_MIPMAP_LINEAR:
- case GL_LINEAR_MIPMAP_LINEAR:
- mipmapping = true;
- break;
- default: UNREACHABLE();
- }
-
- if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
- (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
- {
- if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
- {
- return false;
- }
- }
-
-
- if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
- || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
- {
- return false;
- }
-
- if (mipmapping)
- {
- if (!isPow2(width) || !isPow2(height))
- {
- return false;
- }
-
- int q = log2(std::max(width, height));
-
- for (int level = 1; level <= q; level++)
- {
- if (mImageArray[level].format != mImageArray[0].format)
- {
- return false;
- }
-
- if (mImageArray[level].width != std::max(1, width >> level))
- {
- return false;
- }
-
- if (mImageArray[level].height != std::max(1, height >> level))
- {
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool Texture2D::isCompressed() const
-{
- return IsCompressed(getFormat());
-}
-
-// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
-IDirect3DBaseTexture9 *Texture2D::createTexture()
-{
- IDirect3DTexture9 *texture;
-
- IDirect3DDevice9 *device = getDevice();
- D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
-
- HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- if (mTexture) mTexture->Release();
- mTexture = texture;
- return texture;
-}
-
-void Texture2D::updateTexture()
-{
- IDirect3DDevice9 *device = getDevice();
-
- int levels = levelCount();
-
- for (int level = 0; level < levels; level++)
- {
- if (mImageArray[level].dirty)
- {
- IDirect3DSurface9 *levelSurface = NULL;
- HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
-
- ASSERT(SUCCEEDED(result));
-
- if (SUCCEEDED(result))
- {
- result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
- ASSERT(SUCCEEDED(result));
-
- levelSurface->Release();
-
- mImageArray[level].dirty = false;
- }
- }
- }
-}
-
-IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
-{
- IDirect3DTexture9 *texture = NULL;
-
- if (mWidth != 0 && mHeight != 0)
- {
- egl::Display *display = getDisplay();
- IDirect3DDevice9 *device = getDevice();
- D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
-
- HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- if (mTexture != NULL)
- {
- int levels = levelCount();
- for (int i = 0; i < levels; i++)
- {
- IDirect3DSurface9 *source;
- result = mTexture->GetSurfaceLevel(i, &source);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
- texture->Release();
-
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- IDirect3DSurface9 *dest;
- result = texture->GetSurfaceLevel(i, &dest);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
- texture->Release();
- source->Release();
-
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- display->endScene();
- result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
- texture->Release();
- source->Release();
- dest->Release();
-
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- source->Release();
- dest->Release();
- }
- }
- }
-
- if (mTexture != NULL)
- {
- mTexture->Release();
- }
-
- mTexture = texture;
- return mTexture;
-}
-
-bool Texture2D::dirtyImageData() const
-{
- int q = log2(std::max(mWidth, mHeight));
-
- for (int i = 0; i <= q; i++)
- {
- if (mImageArray[i].dirty) return true;
- }
-
- return false;
-}
-
-void Texture2D::generateMipmaps()
-{
- if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
- {
- return error(GL_INVALID_OPERATION);
- }
-
- // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
- unsigned int q = log2(std::max(mWidth, mHeight));
- for (unsigned int i = 1; i <= q; i++)
- {
- if (mImageArray[i].surface != NULL)
- {
- mImageArray[i].surface->Release();
- mImageArray[i].surface = NULL;
- }
-
- mImageArray[i].dirty = false;
-
- mImageArray[i].format = mImageArray[0].format;
- mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
- mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
- }
-
- if (isRenderable())
- {
- if (mTexture == NULL)
- {
- ERR(" failed because mTexture was null.");
- return;
- }
-
- for (unsigned int i = 1; i <= q; i++)
- {
- IDirect3DSurface9 *upper = NULL;
- IDirect3DSurface9 *lower = NULL;
-
- mTexture->GetSurfaceLevel(i-1, &upper);
- mTexture->GetSurfaceLevel(i, &lower);
-
- if (upper != NULL && lower != NULL)
- {
- getBlitter()->boxFilter(upper, lower);
- }
-
- if (upper != NULL) upper->Release();
- if (lower != NULL) lower->Release();
- }
- }
- else
- {
- for (unsigned int i = 1; i <= q; i++)
- {
- createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
- if (mImageArray[i].surface == NULL)
- {
- return error(GL_OUT_OF_MEMORY);
- }
-
- if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
- {
- ERR(" failed to load filter %d to %d.", i - 1, i);
- }
-
- mImageArray[i].dirty = true;
- }
-
- mDirtyMetaData = true;
- }
-}
-
-Renderbuffer *Texture2D::getColorbuffer(GLenum target)
-{
- if (target != GL_TEXTURE_2D)
- {
- return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
- }
-
- if (mColorbufferProxy.get() == NULL)
- {
- mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
- }
-
- return mColorbufferProxy.get();
-}
-
-IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
-{
- ASSERT(target == GL_TEXTURE_2D);
-
- needRenderTarget();
-
- if (mTexture == NULL)
- {
- return NULL;
- }
-
- IDirect3DSurface9 *renderTarget = NULL;
- mTexture->GetSurfaceLevel(0, &renderTarget);
-
- return renderTarget;
-}
-
-TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
-{
- mTexture = NULL;
-}
-
-TextureCubeMap::~TextureCubeMap()
-{
- for (int i = 0; i < 6; i++)
- {
- mFaceProxies[i].set(NULL);
- }
-
- if (mTexture)
- {
- mTexture->Release();
- mTexture = NULL;
- }
-}
-
-GLenum TextureCubeMap::getTarget() const
-{
- return GL_TEXTURE_CUBE_MAP;
-}
-
-GLenum TextureCubeMap::getFormat() const
-{
- return mImageArray[0][0].format;
-}
-
-void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
-{
- redefineTexture(level, internalFormat, width);
-
- Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
-}
-
-void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
-{
- int face = faceIndex(faceTarget);
- ASSERT(mImageArray[face][level].surface != NULL);
-
- if (level < levelCount())
- {
- IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
- ASSERT(destLevel != NULL);
-
- if (destLevel != NULL)
- {
- Image *img = &mImageArray[face][level];
-
- RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
-
- POINT destPoint;
- destPoint.x = sourceRect.left;
- destPoint.y = sourceRect.top;
-
- HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
- ASSERT(SUCCEEDED(result));
-
- destLevel->Release();
-
- img->dirty = false;
- }
- }
-}
-
-void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
- {
- commitRect(target, level, xoffset, yoffset, width, height);
- }
-}
-
-void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
-{
- if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
- {
- commitRect(target, level, xoffset, yoffset, width, height);
- }
-}
-
-// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
-bool TextureCubeMap::isComplete() const
-{
- int size = mImageArray[0][0].width;
-
- if (size <= 0)
- {
- return false;
- }
-
- bool mipmapping;
-
- switch (mMinFilter)
- {
- case GL_NEAREST:
- case GL_LINEAR:
- mipmapping = false;
- break;
- case GL_NEAREST_MIPMAP_NEAREST:
- case GL_LINEAR_MIPMAP_NEAREST:
- case GL_NEAREST_MIPMAP_LINEAR:
- case GL_LINEAR_MIPMAP_LINEAR:
- mipmapping = true;
- break;
- default: UNREACHABLE();
- }
-
- for (int face = 0; face < 6; face++)
- {
- if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
- {
- return false;
- }
- }
-
- if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
- (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
- {
- if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
- {
- return false;
- }
- }
-
- if (mipmapping)
- {
- if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
- {
- return false;
- }
-
- int q = log2(size);
-
- for (int face = 0; face < 6; face++)
- {
- for (int level = 1; level <= q; level++)
- {
- if (mImageArray[face][level].format != mImageArray[0][0].format)
- {
- return false;
- }
-
- if (mImageArray[face][level].width != std::max(1, size >> level))
- {
- return false;
- }
-
- ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
- }
- }
- }
-
- return true;
-}
-
-bool TextureCubeMap::isCompressed() const
-{
- return IsCompressed(getFormat());
-}
-
-// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
-IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
-{
- IDirect3DDevice9 *device = getDevice();
- D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
-
- IDirect3DCubeTexture9 *texture;
-
- HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- if (mTexture) mTexture->Release();
-
- mTexture = texture;
- return mTexture;
-}
-
-void TextureCubeMap::updateTexture()
-{
- IDirect3DDevice9 *device = getDevice();
-
- for (int face = 0; face < 6; face++)
- {
- int levels = levelCount();
- for (int level = 0; level < levels; level++)
- {
- Image *img = &mImageArray[face][level];
-
- if (img->dirty)
- {
- IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
- ASSERT(levelSurface != NULL);
-
- if (levelSurface != NULL)
- {
- HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
- ASSERT(SUCCEEDED(result));
-
- levelSurface->Release();
-
- img->dirty = false;
- }
- }
- }
- }
-}
-
-IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
-{
- IDirect3DCubeTexture9 *texture = NULL;
-
- if (mWidth != 0)
- {
- egl::Display *display = getDisplay();
- IDirect3DDevice9 *device = getDevice();
- D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
-
- HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- if (mTexture != NULL)
- {
- int levels = levelCount();
- for (int f = 0; f < 6; f++)
- {
- for (int i = 0; i < levels; i++)
- {
- IDirect3DSurface9 *source;
- result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
- texture->Release();
-
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- IDirect3DSurface9 *dest;
- result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
- texture->Release();
- source->Release();
-
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
-
- display->endScene();
- result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
-
- if (FAILED(result))
- {
- ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
- texture->Release();
- source->Release();
- dest->Release();
-
- return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
- }
- }
- }
- }
- }
-
- if (mTexture != NULL)
- {
- mTexture->Release();
- }
-
- mTexture = texture;
- return mTexture;
-}
-
-void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
- redefineTexture(level, internalFormat, width);
-
- Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
-}
-
-unsigned int TextureCubeMap::faceIndex(GLenum face)
-{
- META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
- META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
- META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
- META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
- META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
-
- return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
-}
-
-bool TextureCubeMap::dirtyImageData() const
-{
- int q = log2(mWidth);
-
- for (int f = 0; f < 6; f++)
- {
- for (int i = 0; i <= q; i++)
- {
- if (mImageArray[f][i].dirty) return true;
- }
- }
-
- return false;
-}
-
-// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
-// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
-// Call this when a particular level of the texture must be defined with a specific format, width and height.
-//
-// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
-// a new size for the texture by working backwards from the given size.
-bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
-{
- // Are these settings compatible with level 0?
- bool sizeOkay = (mImageArray[0][0].width >> level == width);
-
- bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
-
- if (!textureOkay)
- {
- TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
- mImageArray[0][0].format, mImageArray[0][0].width,
- internalFormat, width);
-
- // Purge all the levels and the texture.
- for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- for (int f = 0; f < 6; f++)
- {
- if (mImageArray[f][i].surface != NULL)
- {
- mImageArray[f][i].dirty = false;
-
- mImageArray[f][i].surface->Release();
- mImageArray[f][i].surface = NULL;
- }
- }
- }
-
- if (mTexture != NULL)
- {
- mTexture->Release();
- mTexture = NULL;
- dropTexture();
- }
-
- mWidth = width << level;
- mImageArray[0][0].width = width << level;
- mHeight = width << level;
- mImageArray[0][0].height = width << level;
-
- mImageArray[0][0].format = internalFormat;
- }
-
- return !textureOkay;
-}
-
-void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
- IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
- if (!renderTarget)
- {
- ERR("Failed to retrieve the render target.");
- return error(GL_OUT_OF_MEMORY);
- }
-
- unsigned int faceindex = faceIndex(target);
- bool redefined = redefineTexture(level, internalFormat, width);
-
- if (!isRenderableFormat())
- {
- copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
- }
- else
- {
- if (redefined)
- {
- convertToRenderTarget();
- pushTexture(mTexture, true);
- }
- else
- {
- needRenderTarget();
- }
-
- ASSERT(width == height);
-
- if (width > 0 && level < levelCount())
- {
- RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
- sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
- sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
- sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
- sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
- IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
-
- getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
- dest->Release();
- }
- }
-
- mImageArray[faceindex][level].width = width;
- mImageArray[faceindex][level].height = height;
- mImageArray[faceindex][level].format = internalFormat;
-}
-
-IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
-{
- if (mTexture == NULL)
- {
- UNREACHABLE();
- return NULL;
- }
-
- IDirect3DSurface9 *surface = NULL;
-
- HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
-
- return (SUCCEEDED(hr)) ? surface : NULL;
-}
-
-void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
- GLsizei size = mImageArray[faceIndex(target)][level].width;
-
- if (xoffset + width > size || yoffset + height > size)
- {
- return error(GL_INVALID_VALUE);
- }
-
- IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
- if (!renderTarget)
- {
- ERR("Failed to retrieve the render target.");
- return error(GL_OUT_OF_MEMORY);
- }
-
- unsigned int faceindex = faceIndex(target);
- bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
-
- if (!isRenderableFormat())
- {
- copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
- }
- else
- {
- if (redefined)
- {
- convertToRenderTarget();
- pushTexture(mTexture, true);
- }
- else
- {
- needRenderTarget();
- }
-
- if (level < levelCount())
- {
- RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
- sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
- sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
- sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
- sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
- GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
-
- IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
-
- getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
- dest->Release();
- }
- }
-}
-
-bool TextureCubeMap::isCubeComplete() const
-{
- if (mImageArray[0][0].width == 0)
- {
- return false;
- }
-
- for (unsigned int f = 1; f < 6; f++)
- {
- if (mImageArray[f][0].width != mImageArray[0][0].width
- || mImageArray[f][0].format != mImageArray[0][0].format)
- {
- return false;
- }
- }
-
- return true;
-}
-
-void TextureCubeMap::generateMipmaps()
-{
- if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
- {
- return error(GL_INVALID_OPERATION);
- }
-
- // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
- unsigned int q = log2(mImageArray[0][0].width);
- for (unsigned int f = 0; f < 6; f++)
- {
- for (unsigned int i = 1; i <= q; i++)
- {
- if (mImageArray[f][i].surface != NULL)
- {
- mImageArray[f][i].surface->Release();
- mImageArray[f][i].surface = NULL;
- }
-
- mImageArray[f][i].dirty = false;
-
- mImageArray[f][i].format = mImageArray[f][0].format;
- mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
- mImageArray[f][i].height = mImageArray[f][i].width;
- }
- }
-
- if (isRenderable())
- {
- if (mTexture == NULL)
- {
- return;
- }
-
- for (unsigned int f = 0; f < 6; f++)
- {
- for (unsigned int i = 1; i <= q; i++)
- {
- IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
- IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
-
- if (upper != NULL && lower != NULL)
- {
- getBlitter()->boxFilter(upper, lower);
- }
-
- if (upper != NULL) upper->Release();
- if (lower != NULL) lower->Release();
- }
- }
- }
- else
- {
- for (unsigned int f = 0; f < 6; f++)
- {
- for (unsigned int i = 1; i <= q; i++)
- {
- createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
- if (mImageArray[f][i].surface == NULL)
- {
- return error(GL_OUT_OF_MEMORY);
- }
-
- if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
- {
- ERR(" failed to load filter %d to %d.", i - 1, i);
- }
-
- mImageArray[f][i].dirty = true;
- }
- }
-
- mDirtyMetaData = true;
- }
-}
-
-Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
-{
- if (!IsCubemapTextureTarget(target))
- {
- return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
- }
-
- unsigned int face = faceIndex(target);
-
- if (mFaceProxies[face].get() == NULL)
- {
- mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
- }
-
- return mFaceProxies[face].get();
-}
-
-IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
-{
- ASSERT(IsCubemapTextureTarget(target));
-
- needRenderTarget();
-
- if (mTexture == NULL)
- {
- return NULL;
- }
-
- IDirect3DSurface9 *renderTarget = NULL;
- mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
-
- return renderTarget;
-}
-
-Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
- : Colorbuffer(texture), mTexture(texture), mTarget(target)
-{
- ASSERT(IsTextureTarget(target));
-}
-
-void Texture::TextureColorbufferProxy::addRef() const
-{
- mTexture->addRef();
-}
-
-void Texture::TextureColorbufferProxy::release() const
-{
- mTexture->release();
-}
-
-IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
-{
- if (mRenderTarget) mRenderTarget->Release();
-
- mRenderTarget = mTexture->getRenderTarget(mTarget);
-
- return mRenderTarget;
-}
-
-int Texture::TextureColorbufferProxy::getWidth() const
-{
- return mTexture->getWidth();
-}
-
-int Texture::TextureColorbufferProxy::getHeight() const
-{
- return mTexture->getHeight();
-}
-
-GLenum Texture::TextureColorbufferProxy::getFormat() const
-{
- return mTexture->getFormat();
-}
-
-bool Texture::TextureColorbufferProxy::isFloatingPoint() const
-{
- return mTexture->isFloatingPoint();
-}
-
-}
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Texture.cpp: Implements the gl::Texture class and its derived classes
+// Texture2D and TextureCubeMap. Implements GL texture objects and related
+// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
+
+#include "libGLESv2/Texture.h"
+
+#include <d3dx9tex.h>
+
+#include <algorithm>
+
+#include "common/debug.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Blit.h"
+#include "libGLESv2/Framebuffer.h"
+
+namespace gl
+{
+
+Texture::Image::Image()
+ : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
+{
+}
+
+Texture::Image::~Image()
+{
+ if (surface) surface->Release();
+}
+
+Texture::Texture(GLuint id) : RefCountObject(id)
+{
+ mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
+ mMagFilter = GL_LINEAR;
+ mWrapS = GL_REPEAT;
+ mWrapT = GL_REPEAT;
+
+ mWidth = 0;
+ mHeight = 0;
+
+ mDirtyMetaData = true;
+ mDirty = true;
+ mIsRenderable = false;
+ mType = GL_UNSIGNED_BYTE;
+ mBaseTexture = NULL;
+}
+
+Texture::~Texture()
+{
+}
+
+Blit *Texture::getBlitter()
+{
+ Context *context = getContext();
+ return context->getBlitter();
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMinFilter(GLenum filter)
+{
+ switch (filter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ {
+ if (mMinFilter != filter)
+ {
+ mMinFilter = filter;
+ mDirty = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMagFilter(GLenum filter)
+{
+ switch (filter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ {
+ if (mMagFilter != filter)
+ {
+ mMagFilter = filter;
+ mDirty = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapS(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT:
+ case GL_CLAMP_TO_EDGE:
+ case GL_MIRRORED_REPEAT:
+ {
+ if (mWrapS != wrap)
+ {
+ mWrapS = wrap;
+ mDirty = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapT(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT:
+ case GL_CLAMP_TO_EDGE:
+ case GL_MIRRORED_REPEAT:
+ {
+ if (mWrapT != wrap)
+ {
+ mWrapT = wrap;
+ mDirty = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+GLenum Texture::getMinFilter() const
+{
+ return mMinFilter;
+}
+
+GLenum Texture::getMagFilter() const
+{
+ return mMagFilter;
+}
+
+GLenum Texture::getWrapS() const
+{
+ return mWrapS;
+}
+
+GLenum Texture::getWrapT() const
+{
+ return mWrapT;
+}
+
+GLsizei Texture::getWidth() const
+{
+ return mWidth;
+}
+
+GLsizei Texture::getHeight() const
+{
+ return mHeight;
+}
+
+bool Texture::isFloatingPoint() const
+{
+ return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
+}
+
+bool Texture::isRenderableFormat() const
+{
+ D3DFORMAT format = getD3DFormat();
+
+ switch(format)
+ {
+ case D3DFMT_L8:
+ case D3DFMT_A8L8:
+ case D3DFMT_DXT1:
+ return false;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A16B16G16R16F:
+ case D3DFMT_A32B32G32R32F:
+ return true;
+ default:
+ UNREACHABLE();
+ }
+
+ return false;
+}
+
+// Selects an internal Direct3D 9 format for storing an Image
+D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
+{
+ if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+ {
+ return D3DFMT_DXT1;
+ }
+ else if (type == GL_FLOAT)
+ {
+ return D3DFMT_A32B32G32R32F;
+ }
+ else if (type == GL_HALF_FLOAT_OES)
+ {
+ return D3DFMT_A16B16G16R16F;
+ }
+ else if (type == GL_UNSIGNED_BYTE)
+ {
+ if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
+ {
+ return D3DFMT_L8;
+ }
+ else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
+ {
+ return D3DFMT_A8L8;
+ }
+ else if (format == GL_RGB)
+ {
+ return D3DFMT_X8R8G8B8;
+ }
+
+ return D3DFMT_A8R8G8B8;
+ }
+
+ return D3DFMT_A8R8G8B8;
+}
+
+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
+// into the target pixel rectangle at output with outputPitch bytes in between each line.
+void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
+{
+ GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
+ input = ((char*)input) - inputPitch * (height - 1);
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch (format)
+ {
+ case GL_ALPHA:
+ loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
+ break;
+ case GL_RGB:
+ loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGBA:
+ loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_BGRA_EXT:
+ loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5:
+ switch (format)
+ {
+ case GL_RGB:
+ loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ switch (format)
+ {
+ case GL_RGBA:
+ loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ switch (format)
+ {
+ case GL_RGBA:
+ loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT:
+ switch (format)
+ {
+ // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
+ case GL_ALPHA:
+ loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGB:
+ loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGBA:
+ loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_HALF_FLOAT_OES:
+ switch (format)
+ {
+ // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
+ case GL_ALPHA:
+ loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGB:
+ loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGBA:
+ loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = 0;
+ dest[4 * x + 1] = 0;
+ dest[4 * x + 2] = 0;
+ dest[4 * x + 3] = source[x];
+ }
+ }
+}
+
+void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = 0;
+ dest[4 * x + 1] = 0;
+ dest[4 * x + 2] = 0;
+ dest[4 * x + 3] = source[x];
+ }
+ }
+}
+
+void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = 0;
+ dest[4 * x + 1] = 0;
+ dest[4 * x + 2] = 0;
+ dest[4 * x + 3] = source[x];
+ }
+ }
+}
+
+void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
+{
+ const int destBytesPerPixel = native? 1: 4;
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
+
+ if (!native) // BGRA8 destination format
+ {
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x];
+ dest[4 * x + 1] = source[x];
+ dest[4 * x + 2] = source[x];
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+ else // L8 destination format
+ {
+ memcpy(dest, source, width);
+ }
+ }
+}
+
+void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x];
+ dest[4 * x + 1] = source[x];
+ dest[4 * x + 2] = source[x];
+ dest[4 * x + 3] = 1.0f;
+ }
+ }
+}
+
+void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x];
+ dest[4 * x + 1] = source[x];
+ dest[4 * x + 2] = source[x];
+ dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+ }
+ }
+}
+
+void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
+{
+ const int destBytesPerPixel = native? 2: 4;
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
+
+ if (!native) // BGRA8 destination format
+ {
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[2*x+0];
+ dest[4 * x + 1] = source[2*x+0];
+ dest[4 * x + 2] = source[2*x+0];
+ dest[4 * x + 3] = source[2*x+1];
+ }
+ }
+ else
+ {
+ memcpy(dest, source, width * 2);
+ }
+ }
+}
+
+void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[2*x+0];
+ dest[4 * x + 1] = source[2*x+0];
+ dest[4 * x + 2] = source[2*x+0];
+ dest[4 * x + 3] = source[2*x+1];
+ }
+ }
+}
+
+void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[2*x+0];
+ dest[4 * x + 1] = source[2*x+0];
+ dest[4 * x + 2] = source[2*x+0];
+ dest[4 * x + 3] = source[2*x+1];
+ }
+ }
+}
+
+void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 2];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 0];
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
+ dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
+ dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 1.0f;
+ }
+ }
+}
+
+void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+ }
+ }
+}
+
+void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 4 + 2];
+ dest[4 * x + 1] = source[x * 4 + 1];
+ dest[4 * x + 2] = source[x * 4 + 0];
+ dest[4 * x + 3] = source[x * 4 + 3];
+ }
+ }
+}
+
+void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+ dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+ dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+ dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+ }
+ }
+}
+
+void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+ dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+ dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+ }
+ }
+}
+
+void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ memcpy(dest, source, width * 16);
+ }
+}
+
+void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
+ memcpy(dest, source, width * 8);
+ }
+}
+
+void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ memcpy(dest, source, width*4);
+ }
+}
+
+void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ ASSERT(xoffset % 4 == 0);
+ ASSERT(yoffset % 4 == 0);
+ ASSERT(width % 4 == 0 || width == 2 || width == 1);
+ ASSERT(inputPitch % 8 == 0);
+ ASSERT(outputPitch % 8 == 0);
+
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
+ unsigned int *dest = reinterpret_cast<unsigned int*>(output);
+
+ switch (height)
+ {
+ case 1:
+ // Round width up in case it is 1.
+ for (int x = 0; x < (width + 1) / 2; x += 2)
+ {
+ // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
+ dest[x] = source[x];
+
+ // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
+ dest[x + 1] = source[x + 1];
+ }
+ break;
+ case 2:
+ // Round width up in case it is 1.
+ for (int x = 0; x < (width + 1) / 2; x += 2)
+ {
+ // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
+ dest[x] = source[x];
+
+ // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
+ dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
+ ((source[x + 1] >> 8) & 0x000000FF);
+ }
+ break;
+ default:
+ ASSERT(height % 4 == 0);
+ for (int y = 0; y < height / 4; ++y)
+ {
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+
+ // Round width up in case it is 1.
+ for (int x = 0; x < (width + 1) / 2; x += 2)
+ {
+ // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
+ dest[x] = source[x];
+
+ // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
+ dest[x + 1] = (source[x + 1] >> 24) |
+ ((source[x + 1] << 8) & 0x00FF0000) |
+ ((source[x + 1] >> 8) & 0x0000FF00) |
+ (source[x + 1] << 24);
+ }
+ }
+ break;
+ }
+}
+
+void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
+{
+ IDirect3DTexture9 *newTexture = NULL;
+ IDirect3DSurface9 *newSurface = NULL;
+
+ if (width != 0 && height != 0)
+ {
+ int levelToFetch = 0;
+ GLsizei requestWidth = width;
+ GLsizei requestHeight = height;
+ if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
+ {
+ bool isMult4 = false;
+ int upsampleCount = 0;
+ while (!isMult4)
+ {
+ requestWidth <<= 1;
+ requestHeight <<= 1;
+ upsampleCount++;
+ if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
+ {
+ isMult4 = true;
+ }
+ }
+ levelToFetch = upsampleCount;
+ }
+
+ HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
+ D3DPOOL_SYSTEMMEM, &newTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
+ newTexture->Release();
+ }
+
+ if (img->surface) img->surface->Release();
+ img->surface = newSurface;
+
+ img->width = width;
+ img->height = height;
+ img->format = format;
+}
+
+void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
+{
+ createSurface(width, height, format, type, img);
+
+ if (pixels != NULL && img->surface != NULL)
+ {
+ D3DSURFACE_DESC description;
+ img->surface->GetDesc(&description);
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = img->surface->LockRect(&locked, NULL, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
+ img->surface->UnlockRect();
+ }
+
+ img->dirty = true;
+ }
+
+ mDirtyMetaData = true;
+}
+
+void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
+{
+ createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
+
+ if (pixels != NULL && img->surface != NULL)
+ {
+ D3DLOCKED_RECT locked;
+ HRESULT result = img->surface->LockRect(&locked, NULL, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ int inputPitch = ComputeCompressedPitch(width, format);
+ int inputSize = ComputeCompressedSize(width, height, format);
+ loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
+ img->surface->UnlockRect();
+ }
+
+ img->dirty = true;
+ }
+
+ mDirtyMetaData = true;
+}
+
+bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
+{
+ if (width + xoffset > img->width || height + yoffset > img->height)
+ {
+ error(GL_INVALID_VALUE);
+ return false;
+ }
+
+ if (!img->surface)
+ {
+ createSurface(img->width, img->height, format, type, img);
+ }
+
+ if (pixels != NULL && img->surface != NULL)
+ {
+ D3DSURFACE_DESC description;
+ img->surface->GetDesc(&description);
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = img->surface->LockRect(&locked, NULL, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
+ img->surface->UnlockRect();
+ }
+
+ img->dirty = true;
+ }
+
+ return true;
+}
+
+bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
+{
+ if (width + xoffset > img->width || height + yoffset > img->height)
+ {
+ error(GL_INVALID_VALUE);
+ return false;
+ }
+
+ if (format != getInternalFormat())
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ if (!img->surface)
+ {
+ createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
+ }
+
+ if (pixels != NULL && img->surface != NULL)
+ {
+ RECT updateRegion;
+ updateRegion.left = xoffset;
+ updateRegion.right = xoffset + width;
+ updateRegion.bottom = yoffset + height;
+ updateRegion.top = yoffset;
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ int inputPitch = ComputeCompressedPitch(width, format);
+ int inputSize = ComputeCompressedSize(width, height, format);
+ loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
+ img->surface->UnlockRect();
+ }
+
+ img->dirty = true;
+ }
+
+ return true;
+}
+
+// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
+void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
+{
+ IDirect3DDevice9 *device = getDevice();
+ IDirect3DSurface9 *surface = NULL;
+ D3DSURFACE_DESC description;
+ renderTarget->GetDesc(&description);
+
+ HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
+
+ if (!SUCCEEDED(result))
+ {
+ ERR("Could not create matching destination surface.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ result = device->GetRenderTargetData(renderTarget, surface);
+
+ if (!SUCCEEDED(result))
+ {
+ ERR("GetRenderTargetData unexpectedly failed.");
+ surface->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ D3DLOCKED_RECT sourceLock = {0};
+ RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
+ result = surface->LockRect(&sourceLock, &sourceRect, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to lock the source surface (rectangle might be invalid).");
+ surface->UnlockRect();
+ surface->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (!image->surface)
+ {
+ createSurface(width, height, internalFormat, mType, image);
+ }
+
+ if (image->surface == NULL)
+ {
+ ERR("Failed to create an image surface.");
+ surface->UnlockRect();
+ surface->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ D3DLOCKED_RECT destLock = {0};
+ int destYOffset = transformPixelYOffset(yoffset, height, image->height);
+ RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
+ result = image->surface->LockRect(&destLock, &destRect, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to lock the destination surface (rectangle might be invalid).");
+ surface->UnlockRect();
+ surface->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (destLock.pBits && sourceLock.pBits)
+ {
+ unsigned char *source = (unsigned char*)sourceLock.pBits;
+ unsigned char *dest = (unsigned char*)destLock.pBits;
+
+ switch (description.Format)
+ {
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ switch(getD3DFormat())
+ {
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = source[x * 4 + 2];
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ dest[x * 2 + 0] = source[x * 4 + 2];
+ dest[x * 2 + 1] = source[x * 4 + 3];
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_R5G6B5:
+ switch(getD3DFormat())
+ {
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0xF8;
+ dest[x] = red | (red >> 5);
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_A1R5G5B5:
+ switch(getD3DFormat())
+ {
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0x7C;
+ dest[x] = (red << 1) | (red >> 4);
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0x7C;
+ dest[x * 2 + 0] = (red << 1) | (red >> 4);
+ dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ image->dirty = true;
+ mDirtyMetaData = true;
+ }
+
+ image->surface->UnlockRect();
+ surface->UnlockRect();
+ surface->Release();
+}
+
+D3DFORMAT Texture::getD3DFormat() const
+{
+ return selectFormat(getInternalFormat(), mType);
+}
+
+IDirect3DBaseTexture9 *Texture::getTexture()
+{
+ if (!isComplete())
+ {
+ return NULL;
+ }
+
+ if (mDirtyMetaData)
+ {
+ mBaseTexture = createTexture();
+ mIsRenderable = false;
+ }
+
+ if (mDirtyMetaData || dirtyImageData())
+ {
+ updateTexture();
+ }
+
+ mDirtyMetaData = false;
+ ASSERT(!dirtyImageData());
+
+ return mBaseTexture;
+}
+
+bool Texture::isDirty() const
+{
+ return (mDirty || mDirtyMetaData || dirtyImageData());
+}
+
+// Returns the top-level texture surface as a render target
+void Texture::needRenderTarget()
+{
+ if (!mIsRenderable)
+ {
+ mBaseTexture = convertToRenderTarget();
+ mIsRenderable = true;
+ }
+
+ if (dirtyImageData())
+ {
+ updateTexture();
+ }
+
+ mDirtyMetaData = false;
+}
+
+void Texture::dropTexture()
+{
+ if (mBaseTexture)
+ {
+ mBaseTexture = NULL;
+ }
+
+ mIsRenderable = false;
+}
+
+void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
+{
+ mBaseTexture = newTexture;
+ mDirtyMetaData = false;
+ mIsRenderable = renderable;
+ mDirty = true;
+}
+
+
+GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
+{
+ if (isPow2(width) && isPow2(height))
+ {
+ return maxlevel;
+ }
+ else
+ {
+ // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
+ return 1;
+ }
+}
+
+GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
+{
+ return creationLevels(size, size, maxlevel);
+}
+
+int Texture::levelCount() const
+{
+ return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
+}
+
+bool Texture::isRenderable() const
+{
+ return mIsRenderable;
+}
+
+Texture2D::Texture2D(GLuint id) : Texture(id)
+{
+ mTexture = NULL;
+}
+
+Texture2D::~Texture2D()
+{
+ mColorbufferProxy.set(NULL);
+
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+}
+
+GLenum Texture2D::getTarget() const
+{
+ return GL_TEXTURE_2D;
+}
+
+GLenum Texture2D::getInternalFormat() const
+{
+ return mImageArray[0].format;
+}
+
+// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
+// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
+// Call this when a particular level of the texture must be defined with a specific format, width and height.
+//
+// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
+// a new height and width for the texture by working backwards from the given width and height.
+bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
+{
+ bool widthOkay = (mWidth >> level == width);
+ bool heightOkay = (mHeight >> level == height);
+
+ bool sizeOkay = ((widthOkay && heightOkay)
+ || (widthOkay && mHeight >> level == 0 && height == 1)
+ || (heightOkay && mWidth >> level == 0 && width == 1));
+
+ bool typeOkay = (type == mType);
+
+ bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
+
+ if (!textureOkay)
+ {
+ TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
+ mImageArray[0].format, mWidth, mHeight,
+ internalFormat, width, height);
+
+ // Purge all the levels and the texture.
+
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ if (mImageArray[i].surface != NULL)
+ {
+ mImageArray[i].dirty = false;
+
+ mImageArray[i].surface->Release();
+ mImageArray[i].surface = NULL;
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ dropTexture();
+ }
+
+ mWidth = width << level;
+ mHeight = height << level;
+ mImageArray[0].format = internalFormat;
+ mType = type;
+ }
+
+ return !textureOkay;
+}
+
+void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ redefineTexture(level, internalFormat, width, height, type);
+
+ Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
+}
+
+void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
+
+ Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
+}
+
+void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ ASSERT(mImageArray[level].surface != NULL);
+
+ if (level < levelCount())
+ {
+ IDirect3DSurface9 *destLevel = NULL;
+ HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ Image *img = &mImageArray[level];
+
+ RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
+
+ POINT destPoint;
+ destPoint.x = sourceRect.left;
+ destPoint.y = sourceRect.top;
+
+ result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
+ ASSERT(SUCCEEDED(result));
+
+ destLevel->Release();
+
+ img->dirty = false;
+ }
+ }
+}
+
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
+ {
+ commitRect(level, xoffset, yoffset, width, height);
+ }
+}
+
+void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
+ {
+ commitRect(level, xoffset, yoffset, width, height);
+ }
+}
+
+void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ bool redefined = redefineTexture(level, internalFormat, width, height, mType);
+
+ if (!isRenderableFormat())
+ {
+ copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (redefined)
+ {
+ convertToRenderTarget();
+ pushTexture(mTexture, true);
+ }
+ else
+ {
+ needRenderTarget();
+ }
+
+ if (width != 0 && height != 0 && level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ IDirect3DSurface9 *dest;
+ HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
+
+ getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
+ dest->Release();
+ }
+ }
+
+ mImageArray[level].width = width;
+ mImageArray[level].height = height;
+ mImageArray[level].format = internalFormat;
+}
+
+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
+
+ if (!isRenderableFormat())
+ {
+ copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (redefined)
+ {
+ convertToRenderTarget();
+ pushTexture(mTexture, true);
+ }
+ else
+ {
+ needRenderTarget();
+ }
+
+ if (level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
+
+ IDirect3DSurface9 *dest;
+ HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
+
+ getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
+ dest->Release();
+ }
+ }
+}
+
+// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool Texture2D::isComplete() const
+{
+ GLsizei width = mImageArray[0].width;
+ GLsizei height = mImageArray[0].height;
+
+ if (width <= 0 || height <= 0)
+ {
+ return false;
+ }
+
+ bool mipmapping = false;
+
+ switch (mMinFilter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ mipmapping = false;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ mipmapping = true;
+ break;
+ default: UNREACHABLE();
+ }
+
+ if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
+ (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
+ {
+ if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
+ {
+ return false;
+ }
+ }
+
+
+ if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
+ || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
+ {
+ return false;
+ }
+
+ if (mipmapping)
+ {
+ if (!isPow2(width) || !isPow2(height))
+ {
+ return false;
+ }
+
+ int q = log2(std::max(width, height));
+
+ for (int level = 1; level <= q; level++)
+ {
+ if (mImageArray[level].format != mImageArray[0].format)
+ {
+ return false;
+ }
+
+ if (mImageArray[level].width != std::max(1, width >> level))
+ {
+ return false;
+ }
+
+ if (mImageArray[level].height != std::max(1, height >> level))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool Texture2D::isCompressed() const
+{
+ return IsCompressed(getInternalFormat());
+}
+
+// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
+IDirect3DBaseTexture9 *Texture2D::createTexture()
+{
+ IDirect3DTexture9 *texture;
+
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
+
+ HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ if (mTexture) mTexture->Release();
+ mTexture = texture;
+ return texture;
+}
+
+void Texture2D::updateTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ int levels = levelCount();
+
+ for (int level = 0; level < levels; level++)
+ {
+ if (mImageArray[level].dirty)
+ {
+ IDirect3DSurface9 *levelSurface = NULL;
+ HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
+ ASSERT(SUCCEEDED(result));
+
+ levelSurface->Release();
+
+ mImageArray[level].dirty = false;
+ }
+ }
+ }
+}
+
+IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
+{
+ IDirect3DTexture9 *texture = NULL;
+
+ if (mWidth != 0 && mHeight != 0)
+ {
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
+
+ HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ if (mTexture != NULL)
+ {
+ int levels = levelCount();
+ for (int i = 0; i < levels; i++)
+ {
+ IDirect3DSurface9 *source;
+ result = mTexture->GetSurfaceLevel(i, &source);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ IDirect3DSurface9 *dest;
+ result = texture->GetSurfaceLevel(i, &dest);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ display->endScene();
+ result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+ dest->Release();
+
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ source->Release();
+ dest->Release();
+ }
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ }
+
+ mTexture = texture;
+ return mTexture;
+}
+
+bool Texture2D::dirtyImageData() const
+{
+ int q = log2(std::max(mWidth, mHeight));
+
+ for (int i = 0; i <= q; i++)
+ {
+ if (mImageArray[i].dirty) return true;
+ }
+
+ return false;
+}
+
+void Texture2D::generateMipmaps()
+{
+ if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
+ unsigned int q = log2(std::max(mWidth, mHeight));
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ if (mImageArray[i].surface != NULL)
+ {
+ mImageArray[i].surface->Release();
+ mImageArray[i].surface = NULL;
+ }
+
+ mImageArray[i].dirty = false;
+
+ mImageArray[i].format = mImageArray[0].format;
+ mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
+ mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
+ }
+
+ if (isRenderable())
+ {
+ if (mTexture == NULL)
+ {
+ ERR(" failed because mTexture was null.");
+ return;
+ }
+
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ IDirect3DSurface9 *upper = NULL;
+ IDirect3DSurface9 *lower = NULL;
+
+ mTexture->GetSurfaceLevel(i-1, &upper);
+ mTexture->GetSurfaceLevel(i, &lower);
+
+ if (upper != NULL && lower != NULL)
+ {
+ getBlitter()->boxFilter(upper, lower);
+ }
+
+ if (upper != NULL) upper->Release();
+ if (lower != NULL) lower->Release();
+ }
+ }
+ else
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
+ if (mImageArray[i].surface == NULL)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
+ {
+ ERR(" failed to load filter %d to %d.", i - 1, i);
+ }
+
+ mImageArray[i].dirty = true;
+ }
+
+ mDirtyMetaData = true;
+ }
+}
+
+Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
+{
+ if (target != GL_TEXTURE_2D)
+ {
+ return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ if (mColorbufferProxy.get() == NULL)
+ {
+ mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
+ }
+
+ return mColorbufferProxy.get();
+}
+
+IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+
+ needRenderTarget();
+
+ if (mTexture == NULL)
+ {
+ return NULL;
+ }
+
+ IDirect3DSurface9 *renderTarget = NULL;
+ mTexture->GetSurfaceLevel(0, &renderTarget);
+
+ return renderTarget;
+}
+
+TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
+{
+ mTexture = NULL;
+}
+
+TextureCubeMap::~TextureCubeMap()
+{
+ for (int i = 0; i < 6; i++)
+ {
+ mFaceProxies[i].set(NULL);
+ }
+
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+}
+
+GLenum TextureCubeMap::getTarget() const
+{
+ return GL_TEXTURE_CUBE_MAP;
+}
+
+GLenum TextureCubeMap::getInternalFormat() const
+{
+ return mImageArray[0][0].format;
+}
+
+void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ redefineTexture(level, internalFormat, width);
+
+ Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
+}
+
+void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ int face = faceIndex(faceTarget);
+ ASSERT(mImageArray[face][level].surface != NULL);
+
+ if (level < levelCount())
+ {
+ IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
+ ASSERT(destLevel != NULL);
+
+ if (destLevel != NULL)
+ {
+ Image *img = &mImageArray[face][level];
+
+ RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
+
+ POINT destPoint;
+ destPoint.x = sourceRect.left;
+ destPoint.y = sourceRect.top;
+
+ HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
+ ASSERT(SUCCEEDED(result));
+
+ destLevel->Release();
+
+ img->dirty = false;
+ }
+ }
+}
+
+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
+ {
+ commitRect(target, level, xoffset, yoffset, width, height);
+ }
+}
+
+void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
+ {
+ commitRect(target, level, xoffset, yoffset, width, height);
+ }
+}
+
+// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool TextureCubeMap::isComplete() const
+{
+ int size = mImageArray[0][0].width;
+
+ if (size <= 0)
+ {
+ return false;
+ }
+
+ bool mipmapping;
+
+ switch (mMinFilter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ mipmapping = false;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ mipmapping = true;
+ break;
+ default: UNREACHABLE();
+ }
+
+ for (int face = 0; face < 6; face++)
+ {
+ if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
+ {
+ return false;
+ }
+ }
+
+ if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
+ (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
+ {
+ if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
+ {
+ return false;
+ }
+ }
+
+ if (mipmapping)
+ {
+ if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
+ {
+ return false;
+ }
+
+ int q = log2(size);
+
+ for (int face = 0; face < 6; face++)
+ {
+ for (int level = 1; level <= q; level++)
+ {
+ if (mImageArray[face][level].format != mImageArray[0][0].format)
+ {
+ return false;
+ }
+
+ if (mImageArray[face][level].width != std::max(1, size >> level))
+ {
+ return false;
+ }
+
+ ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool TextureCubeMap::isCompressed() const
+{
+ return IsCompressed(getInternalFormat());
+}
+
+// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
+IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
+
+ IDirect3DCubeTexture9 *texture;
+
+ HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ if (mTexture) mTexture->Release();
+
+ mTexture = texture;
+ return mTexture;
+}
+
+void TextureCubeMap::updateTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ for (int face = 0; face < 6; face++)
+ {
+ int levels = levelCount();
+ for (int level = 0; level < levels; level++)
+ {
+ Image *img = &mImageArray[face][level];
+
+ if (img->dirty)
+ {
+ IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
+ ASSERT(levelSurface != NULL);
+
+ if (levelSurface != NULL)
+ {
+ HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
+ ASSERT(SUCCEEDED(result));
+
+ levelSurface->Release();
+
+ img->dirty = false;
+ }
+ }
+ }
+ }
+}
+
+IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
+{
+ IDirect3DCubeTexture9 *texture = NULL;
+
+ if (mWidth != 0)
+ {
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
+
+ HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ if (mTexture != NULL)
+ {
+ int levels = levelCount();
+ for (int f = 0; f < 6; f++)
+ {
+ for (int i = 0; i < levels; i++)
+ {
+ IDirect3DSurface9 *source;
+ result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ IDirect3DSurface9 *dest;
+ result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+
+ display->endScene();
+ result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+ dest->Release();
+
+ return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
+ }
+ }
+ }
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ }
+
+ mTexture = texture;
+ return mTexture;
+}
+
+void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ redefineTexture(level, internalFormat, width);
+
+ Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
+}
+
+unsigned int TextureCubeMap::faceIndex(GLenum face)
+{
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
+
+ return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+}
+
+bool TextureCubeMap::dirtyImageData() const
+{
+ int q = log2(mWidth);
+
+ for (int f = 0; f < 6; f++)
+ {
+ for (int i = 0; i <= q; i++)
+ {
+ if (mImageArray[f][i].dirty) return true;
+ }
+ }
+
+ return false;
+}
+
+// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
+// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
+// Call this when a particular level of the texture must be defined with a specific format, width and height.
+//
+// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
+// a new size for the texture by working backwards from the given size.
+bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
+{
+ // Are these settings compatible with level 0?
+ bool sizeOkay = (mImageArray[0][0].width >> level == width);
+
+ bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
+
+ if (!textureOkay)
+ {
+ TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
+ mImageArray[0][0].format, mImageArray[0][0].width,
+ internalFormat, width);
+
+ // Purge all the levels and the texture.
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ for (int f = 0; f < 6; f++)
+ {
+ if (mImageArray[f][i].surface != NULL)
+ {
+ mImageArray[f][i].dirty = false;
+
+ mImageArray[f][i].surface->Release();
+ mImageArray[f][i].surface = NULL;
+ }
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ dropTexture();
+ }
+
+ mWidth = width << level;
+ mImageArray[0][0].width = width << level;
+ mHeight = width << level;
+ mImageArray[0][0].height = width << level;
+
+ mImageArray[0][0].format = internalFormat;
+ }
+
+ return !textureOkay;
+}
+
+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ unsigned int faceindex = faceIndex(target);
+ bool redefined = redefineTexture(level, internalFormat, width);
+
+ if (!isRenderableFormat())
+ {
+ copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (redefined)
+ {
+ convertToRenderTarget();
+ pushTexture(mTexture, true);
+ }
+ else
+ {
+ needRenderTarget();
+ }
+
+ ASSERT(width == height);
+
+ if (width > 0 && level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
+
+ getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
+ dest->Release();
+ }
+ }
+
+ mImageArray[faceindex][level].width = width;
+ mImageArray[faceindex][level].height = height;
+ mImageArray[faceindex][level].format = internalFormat;
+}
+
+IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
+{
+ if (mTexture == NULL)
+ {
+ UNREACHABLE();
+ return NULL;
+ }
+
+ IDirect3DSurface9 *surface = NULL;
+
+ HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
+
+ return (SUCCEEDED(hr)) ? surface : NULL;
+}
+
+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ GLsizei size = mImageArray[faceIndex(target)][level].width;
+
+ if (xoffset + width > size || yoffset + height > size)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ unsigned int faceindex = faceIndex(target);
+ bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
+
+ if (!isRenderableFormat())
+ {
+ copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (redefined)
+ {
+ convertToRenderTarget();
+ pushTexture(mTexture, true);
+ }
+ else
+ {
+ needRenderTarget();
+ }
+
+ if (level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
+
+ IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
+
+ getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
+ dest->Release();
+ }
+ }
+}
+
+bool TextureCubeMap::isCubeComplete() const
+{
+ if (mImageArray[0][0].width == 0)
+ {
+ return false;
+ }
+
+ for (unsigned int f = 1; f < 6; f++)
+ {
+ if (mImageArray[f][0].width != mImageArray[0][0].width
+ || mImageArray[f][0].format != mImageArray[0][0].format)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TextureCubeMap::generateMipmaps()
+{
+ if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
+ unsigned int q = log2(mImageArray[0][0].width);
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ if (mImageArray[f][i].surface != NULL)
+ {
+ mImageArray[f][i].surface->Release();
+ mImageArray[f][i].surface = NULL;
+ }
+
+ mImageArray[f][i].dirty = false;
+
+ mImageArray[f][i].format = mImageArray[f][0].format;
+ mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
+ mImageArray[f][i].height = mImageArray[f][i].width;
+ }
+ }
+
+ if (isRenderable())
+ {
+ if (mTexture == NULL)
+ {
+ return;
+ }
+
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
+ IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
+
+ if (upper != NULL && lower != NULL)
+ {
+ getBlitter()->boxFilter(upper, lower);
+ }
+
+ if (upper != NULL) upper->Release();
+ if (lower != NULL) lower->Release();
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
+ if (mImageArray[f][i].surface == NULL)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
+ {
+ ERR(" failed to load filter %d to %d.", i - 1, i);
+ }
+
+ mImageArray[f][i].dirty = true;
+ }
+ }
+
+ mDirtyMetaData = true;
+ }
+}
+
+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
+{
+ if (!IsCubemapTextureTarget(target))
+ {
+ return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ unsigned int face = faceIndex(target);
+
+ if (mFaceProxies[face].get() == NULL)
+ {
+ mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
+ }
+
+ return mFaceProxies[face].get();
+}
+
+IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
+{
+ ASSERT(IsCubemapTextureTarget(target));
+
+ needRenderTarget();
+
+ if (mTexture == NULL)
+ {
+ return NULL;
+ }
+
+ IDirect3DSurface9 *renderTarget = NULL;
+ mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
+
+ return renderTarget;
+}
+
+}
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index 1fd42e0..4060b32 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -57,10 +57,10 @@
GLenum getWrapS() const;
GLenum getWrapT() const;
- GLuint getWidth() const;
- GLuint getHeight() const;
+ GLsizei getWidth() const;
+ GLsizei getHeight() const;
- virtual GLenum getFormat() const = 0;
+ virtual GLenum getInternalFormat() const = 0;
virtual bool isComplete() const = 0;
virtual bool isCompressed() const = 0;
bool isFloatingPoint() const;
@@ -68,38 +68,17 @@
D3DFORMAT getD3DFormat() const;
IDirect3DBaseTexture9 *getTexture();
- virtual Renderbuffer *getColorbuffer(GLenum target) = 0;
+ virtual Renderbuffer *getRenderbuffer(GLenum target) = 0;
virtual void generateMipmaps() = 0;
virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;
bool isDirty() const;
- static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager.
+ static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager.
protected:
- class TextureColorbufferProxy;
- friend class TextureColorbufferProxy;
- class TextureColorbufferProxy : public Colorbuffer
- {
- public:
- TextureColorbufferProxy(Texture *texture, GLenum target);
- // target is a 2D-like texture target (GL_TEXTURE_2D or one of the cube face targets)
-
- virtual void addRef() const;
- virtual void release() const;
-
- virtual IDirect3DSurface9 *getRenderTarget();
-
- virtual int getWidth() const;
- virtual int getHeight() const;
- virtual GLenum getFormat() const;
- virtual bool isFloatingPoint() const;
-
- private:
- Texture *mTexture;
- GLenum mTarget;
- };
+ friend class Colorbuffer;
// Helper structure representing a single image layer
struct Image
@@ -147,8 +126,8 @@
bool isRenderable() const;
- unsigned int mWidth;
- unsigned int mHeight;
+ GLsizei mWidth;
+ GLsizei mHeight;
GLenum mMinFilter;
GLenum mMagFilter;
GLenum mWrapS;
@@ -218,7 +197,7 @@
~Texture2D();
GLenum getTarget() const;
- GLenum getFormat() const;
+ GLenum getInternalFormat() const;
void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
@@ -232,7 +211,7 @@
virtual void generateMipmaps();
- virtual Renderbuffer *getColorbuffer(GLenum target);
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
private:
DISALLOW_COPY_AND_ASSIGN(Texture2D);
@@ -262,7 +241,7 @@
~TextureCubeMap();
GLenum getTarget() const;
- GLenum getFormat() const;
+ GLenum getInternalFormat() const;
void setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
@@ -283,7 +262,7 @@
virtual void generateMipmaps();
- virtual Renderbuffer *getColorbuffer(GLenum target);
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
private:
DISALLOW_COPY_AND_ASSIGN(TextureCubeMap);
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index cfc3a45..9ab0abe 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -1044,7 +1044,7 @@
}
gl::Colorbuffer *source = framebuffer->getColorbuffer();
- GLenum colorbufferFormat = source->getFormat();
+ GLenum colorbufferFormat = source->getInternalFormat();
// [OpenGL ES 2.0.24] table 3.9
switch (internalformat)
@@ -1178,7 +1178,7 @@
}
gl::Colorbuffer *source = framebuffer->getColorbuffer();
- GLenum colorbufferFormat = source->getFormat();
+ GLenum colorbufferFormat = source->getInternalFormat();
gl::Texture *texture = NULL;
if (target == GL_TEXTURE_2D)
@@ -1196,7 +1196,7 @@
return error(GL_INVALID_OPERATION);
}
- GLenum textureFormat = texture->getFormat();
+ GLenum textureFormat = texture->getInternalFormat();
// [OpenGL ES 2.0.24] table 3.9
switch (textureFormat)
@@ -2954,85 +2954,23 @@
switch (pname)
{
- case GL_RENDERBUFFER_WIDTH:
- *params = renderbuffer->getWidth();
- break;
- case GL_RENDERBUFFER_HEIGHT:
- *params = renderbuffer->getHeight();
- break;
- case GL_RENDERBUFFER_INTERNAL_FORMAT:
- *params = renderbuffer->getFormat();
- break;
- case GL_RENDERBUFFER_RED_SIZE:
- if (renderbuffer->isColorbuffer())
- {
- *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getRedSize();
- }
- else
- {
- *params = 0;
- }
- break;
- case GL_RENDERBUFFER_GREEN_SIZE:
- if (renderbuffer->isColorbuffer())
- {
- *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getGreenSize();
- }
- else
- {
- *params = 0;
- }
- break;
- case GL_RENDERBUFFER_BLUE_SIZE:
- if (renderbuffer->isColorbuffer())
- {
- *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getBlueSize();
- }
- else
- {
- *params = 0;
- }
- break;
- case GL_RENDERBUFFER_ALPHA_SIZE:
- if (renderbuffer->isColorbuffer())
- {
- *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getAlphaSize();
- }
- else
- {
- *params = 0;
- }
- break;
- case GL_RENDERBUFFER_DEPTH_SIZE:
- if (renderbuffer->isDepthbuffer())
- {
- *params = static_cast<gl::Depthbuffer*>(renderbuffer->getStorage())->getDepthSize();
- }
- else
- {
- *params = 0;
- }
- break;
- case GL_RENDERBUFFER_STENCIL_SIZE:
- if (renderbuffer->isStencilbuffer())
- {
- *params = static_cast<gl::Stencilbuffer*>(renderbuffer->getStorage())->getStencilSize();
- }
- else
- {
- *params = 0;
- }
- break;
+ case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break;
+ case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break;
+ case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break;
+ case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break;
+ case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break;
+ case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break;
+ case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break;
+ case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break;
+ case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break;
case GL_RENDERBUFFER_SAMPLES_ANGLE:
+ if (context->getMaxSupportedSamples() != 0)
{
- if (context->getMaxSupportedSamples() != 0)
- {
- *params = renderbuffer->getStorage()->getSamples();
- }
- else
- {
- return error(GL_INVALID_ENUM);
- }
+ *params = renderbuffer->getSamples();
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
}
break;
default:
@@ -4797,7 +4735,7 @@
return error(GL_INVALID_OPERATION);
}
- if (format != texture->getFormat())
+ if (format != texture->getInternalFormat())
{
return error(GL_INVALID_OPERATION);
}
@@ -4818,7 +4756,7 @@
return error(GL_INVALID_OPERATION);
}
- if (format != texture->getFormat())
+ if (format != texture->getInternalFormat())
{
return error(GL_INVALID_OPERATION);
}
diff --git a/src/libGLESv2/utilities.cpp b/src/libGLESv2/utilities.cpp
index f0f940b..ae1df8e 100644
--- a/src/libGLESv2/utilities.cpp
+++ b/src/libGLESv2/utilities.cpp
@@ -608,6 +608,75 @@
}
}
+bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
+ D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount)
+{
+ switch (primitiveType)
+ {
+ case GL_POINTS:
+ *d3dPrimitiveType = D3DPT_POINTLIST;
+ *d3dPrimitiveCount = elementCount;
+ break;
+ case GL_LINES:
+ *d3dPrimitiveType = D3DPT_LINELIST;
+ *d3dPrimitiveCount = elementCount / 2;
+ break;
+ case GL_LINE_LOOP:
+ *d3dPrimitiveType = D3DPT_LINESTRIP;
+ *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately
+ break;
+ case GL_LINE_STRIP:
+ *d3dPrimitiveType = D3DPT_LINESTRIP;
+ *d3dPrimitiveCount = elementCount - 1;
+ break;
+ case GL_TRIANGLES:
+ *d3dPrimitiveType = D3DPT_TRIANGLELIST;
+ *d3dPrimitiveCount = elementCount / 3;
+ break;
+ case GL_TRIANGLE_STRIP:
+ *d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
+ *d3dPrimitiveCount = elementCount - 2;
+ break;
+ case GL_TRIANGLE_FAN:
+ *d3dPrimitiveType = D3DPT_TRIANGLEFAN;
+ *d3dPrimitiveCount = elementCount - 2;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+D3DFORMAT ConvertRenderbufferFormat(GLenum format)
+{
+ switch (format)
+ {
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8_OES: return D3DFMT_A8R8G8B8;
+ case GL_RGB565: return D3DFMT_R5G6B5;
+ case GL_RGB8_OES: return D3DFMT_X8R8G8B8;
+ case GL_DEPTH_COMPONENT16:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
+ default: UNREACHABLE(); return D3DFMT_A8R8G8B8;
+ }
+}
+
+D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples)
+{
+ if (samples <= 1)
+ return D3DMULTISAMPLE_NONE;
+ else
+ return (D3DMULTISAMPLE_TYPE)samples;
+}
+
+}
+
+namespace dx2es
+{
+
unsigned int GetStencilSize(D3DFORMAT stencilFormat)
{
switch(stencilFormat)
@@ -625,8 +694,8 @@
case D3DFMT_D32F_LOCKABLE:
case D3DFMT_D16:
return 0;
-// case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only
-// case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only
+ //case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only
+ //case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only
default: UNREACHABLE();
}
return 0;
@@ -739,62 +808,6 @@
return 0;
}
-bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
- D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount)
-{
- switch (primitiveType)
- {
- case GL_POINTS:
- *d3dPrimitiveType = D3DPT_POINTLIST;
- *d3dPrimitiveCount = elementCount;
- break;
- case GL_LINES:
- *d3dPrimitiveType = D3DPT_LINELIST;
- *d3dPrimitiveCount = elementCount / 2;
- break;
- case GL_LINE_LOOP:
- *d3dPrimitiveType = D3DPT_LINESTRIP;
- *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately
- break;
- case GL_LINE_STRIP:
- *d3dPrimitiveType = D3DPT_LINESTRIP;
- *d3dPrimitiveCount = elementCount - 1;
- break;
- case GL_TRIANGLES:
- *d3dPrimitiveType = D3DPT_TRIANGLELIST;
- *d3dPrimitiveCount = elementCount / 3;
- break;
- case GL_TRIANGLE_STRIP:
- *d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
- *d3dPrimitiveCount = elementCount - 2;
- break;
- case GL_TRIANGLE_FAN:
- *d3dPrimitiveType = D3DPT_TRIANGLEFAN;
- *d3dPrimitiveCount = elementCount - 2;
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-D3DFORMAT ConvertRenderbufferFormat(GLenum format)
-{
- switch (format)
- {
- case GL_RGBA4:
- case GL_RGB5_A1:
- case GL_RGBA8_OES: return D3DFMT_A8R8G8B8;
- case GL_RGB565: return D3DFMT_R5G6B5;
- case GL_RGB8_OES: return D3DFMT_X8R8G8B8;
- case GL_DEPTH_COMPONENT16:
- case GL_STENCIL_INDEX8:
- case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
- default: UNREACHABLE(); return D3DFMT_A8R8G8B8;
- }
-}
-
GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type)
{
if (type == D3DMULTISAMPLE_NONMASKABLE)
@@ -803,19 +816,6 @@
return type;
}
-D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples)
-{
- if (samples <= 1)
- return D3DMULTISAMPLE_NONE;
- else
- return (D3DMULTISAMPLE_TYPE)samples;
-}
-
-}
-
-namespace dx2es
-{
-
GLenum ConvertBackBufferFormat(D3DFORMAT format)
{
switch (format)
@@ -852,33 +852,33 @@
std::string getTempPath()
{
- char path[MAX_PATH];
- DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
- if (pathLen == 0)
- {
- UNREACHABLE();
- return std::string();
- }
-
- UINT unique = GetTempFileNameA(path, "sh", 0, path);
- if (unique == 0)
- {
- UNREACHABLE();
- return std::string();
- }
-
- return path;
+ char path[MAX_PATH];
+ DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
+ if (pathLen == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
+
+ UINT unique = GetTempFileNameA(path, "sh", 0, path);
+ if (unique == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
+
+ return path;
}
void writeFile(const char* path, const void* content, size_t size)
-{
- FILE* file = fopen(path, "w");
- if (!file)
- {
- UNREACHABLE();
- return;
- }
-
- fwrite(content, sizeof(char), size, file);
- fclose(file);
+{
+ FILE* file = fopen(path, "w");
+ if (!file)
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ fwrite(content, sizeof(char), size, file);
+ fclose(file);
}
diff --git a/src/libGLESv2/utilities.h b/src/libGLESv2/utilities.h
index ea75900..bf7f4f9 100644
--- a/src/libGLESv2/utilities.h
+++ b/src/libGLESv2/utilities.h
@@ -58,22 +58,23 @@
DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha);
D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter);
void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter);
-unsigned int GetAlphaSize(D3DFORMAT colorFormat);
-unsigned int GetRedSize(D3DFORMAT colorFormat);
-unsigned int GetGreenSize(D3DFORMAT colorFormat);
-unsigned int GetBlueSize(D3DFORMAT colorFormat);
-unsigned int GetDepthSize(D3DFORMAT depthFormat);
-unsigned int GetStencilSize(D3DFORMAT stencilFormat);
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount);
D3DFORMAT ConvertRenderbufferFormat(GLenum format);
D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples);
-GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type);
}
namespace dx2es
{
+GLuint GetAlphaSize(D3DFORMAT colorFormat);
+GLuint GetRedSize(D3DFORMAT colorFormat);
+GLuint GetGreenSize(D3DFORMAT colorFormat);
+GLuint GetBlueSize(D3DFORMAT colorFormat);
+GLuint GetDepthSize(D3DFORMAT depthFormat);
+GLuint GetStencilSize(D3DFORMAT stencilFormat);
+
+GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type);
GLenum ConvertBackBufferFormat(D3DFORMAT format);
GLenum ConvertDepthStencilFormat(D3DFORMAT format);