Implement support for mipmap generation

TRAC #11338 Signed-off-by: Nicolas Capens Signed-off-by: Daniel Koch Author: Andrew Lewycky git-svn-id: https://angleproject.googlecode.com/svn/trunk@161 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 5d2bee93
...@@ -238,6 +238,48 @@ bool Blit::setPixelShader(ShaderId shader) ...@@ -238,6 +238,48 @@ bool Blit::setPixelShader(ShaderId shader)
return setShader<IDirect3DPixelShader9>(shader, mContext->getPixelShaderProfile(), &IDirect3DDevice9::CreatePixelShader, &IDirect3DDevice9::SetPixelShader); return setShader<IDirect3DPixelShader9>(shader, mContext->getPixelShaderProfile(), &IDirect3DDevice9::CreatePixelShader, &IDirect3DDevice9::SetPixelShader);
} }
RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const
{
D3DSURFACE_DESC desc;
surface->GetDesc(&desc);
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = desc.Width;
rect.bottom = desc.Height;
return rect;
}
bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
{
IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
if (!texture)
{
return false;
}
IDirect3DDevice9 *device = getDevice();
device->SetTexture(0, texture);
device->SetRenderTarget(0, dest);
setVertexShader(SHADER_VS_STANDARD);
setPixelShader(SHADER_PS_PASSTHROUGH);
setCommonBlitState();
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
setViewport(getSurfaceRect(dest), 0, 0);
render();
texture->Release();
return true;
}
bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
{ {
IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
...@@ -251,7 +293,7 @@ bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLen ...@@ -251,7 +293,7 @@ bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLen
device->SetTexture(0, texture); device->SetTexture(0, texture);
device->SetRenderTarget(0, dest); device->SetRenderTarget(0, dest);
setViewport(sourceRect, xoffset, yoffset, dest); setViewport(sourceRect, xoffset, yoffset);
setCommonBlitState(); setCommonBlitState();
if (setFormatConvertShaders(destFormat)) if (setFormatConvertShaders(destFormat))
...@@ -334,7 +376,7 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const ...@@ -334,7 +376,7 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const
// Copy the render target into a texture // Copy the render target into a texture
IDirect3DTexture9 *texture; IDirect3DTexture9 *texture;
HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.top - sourceRect.bottom, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL); HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
if (FAILED(result)) if (FAILED(result))
{ {
...@@ -355,8 +397,8 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const ...@@ -355,8 +397,8 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const
RECT d3dSourceRect; RECT d3dSourceRect;
d3dSourceRect.left = sourceRect.left; d3dSourceRect.left = sourceRect.left;
d3dSourceRect.right = sourceRect.right; d3dSourceRect.right = sourceRect.right;
d3dSourceRect.top = sourceRect.bottom; d3dSourceRect.top = sourceRect.top;
d3dSourceRect.bottom = sourceRect.top; d3dSourceRect.bottom = sourceRect.bottom;
result = device->StretchRect(surface, &d3dSourceRect, textureSurface, NULL, D3DTEXF_NONE); result = device->StretchRect(surface, &d3dSourceRect, textureSurface, NULL, D3DTEXF_NONE);
...@@ -372,18 +414,15 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const ...@@ -372,18 +414,15 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const
return texture; return texture;
} }
void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
{ {
D3DSURFACE_DESC desc;
dest->GetDesc(&desc);
IDirect3DDevice9 *device = getDevice(); IDirect3DDevice9 *device = getDevice();
D3DVIEWPORT9 vp; D3DVIEWPORT9 vp;
vp.X = xoffset; vp.X = xoffset;
vp.Y = yoffset; vp.Y = yoffset;
vp.Width = sourceRect.right - sourceRect.left; vp.Width = sourceRect.right - sourceRect.left;
vp.Height = sourceRect.top - sourceRect.bottom; vp.Height = sourceRect.bottom - sourceRect.top;
vp.MinZ = 0.0f; vp.MinZ = 0.0f;
vp.MaxZ = 1.0f; vp.MaxZ = 1.0f;
device->SetViewport(&vp); device->SetViewport(&vp);
...@@ -410,6 +449,8 @@ void Blit::setCommonBlitState() ...@@ -410,6 +449,8 @@ void Blit::setCommonBlitState()
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
} }
void Blit::render() void Blit::render()
......
...@@ -29,10 +29,14 @@ class Blit ...@@ -29,10 +29,14 @@ class Blit
~Blit(); ~Blit();
// Copy from source surface to dest surface. // Copy from source surface to dest surface.
// sourceRect, xoffset, yoffset are in OpenGL coordinates. Assumes that source is internally flipped (for example as a render target would be). // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left)
// source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0.
bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest);
// 2x2 box filter sample from source to dest.
// Requires that source is RGB(A) and dest has the same format as source.
bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
private: private:
Context *mContext; Context *mContext;
...@@ -44,8 +48,9 @@ class Blit ...@@ -44,8 +48,9 @@ class Blit
bool setFormatConvertShaders(GLenum destFormat); bool setFormatConvertShaders(GLenum destFormat);
IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect); IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect);
void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset);
void setCommonBlitState(); void setCommonBlitState();
RECT getSurfaceRect(IDirect3DSurface9 *surface) const;
// This enum is used to index mCompiledShaders and mShaderSource. // This enum is used to index mCompiledShaders and mShaderSource.
enum ShaderId enum ShaderId
......
...@@ -549,9 +549,9 @@ void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, ...@@ -549,9 +549,9 @@ void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y,
{ {
RECT sourceRect; RECT sourceRect;
sourceRect.left = x; sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width; sourceRect.right = x + width;
sourceRect.bottom = y; sourceRect.top = source->getHeight() - (y + height);
sourceRect.bottom = source->getHeight() - y;
IDirect3DSurface9 *dest; IDirect3DSurface9 *dest;
HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
...@@ -584,9 +584,9 @@ void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, ...@@ -584,9 +584,9 @@ void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x,
RECT sourceRect; RECT sourceRect;
sourceRect.left = x; sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width; sourceRect.right = x + width;
sourceRect.bottom = y; sourceRect.top = source->getHeight() - (y + height);
sourceRect.bottom = source->getHeight() - y;
IDirect3DSurface9 *dest; IDirect3DSurface9 *dest;
HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
...@@ -796,6 +796,50 @@ bool Texture2D::dirtyImageData() const ...@@ -796,6 +796,50 @@ bool Texture2D::dirtyImageData() const
return false; 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);
}
getRenderTarget();
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();
}
}
TextureCubeMap::TextureCubeMap(Context *context) : Texture(context) TextureCubeMap::TextureCubeMap(Context *context) : Texture(context)
{ {
mTexture = NULL; mTexture = NULL;
...@@ -1184,9 +1228,9 @@ void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, ...@@ -1184,9 +1228,9 @@ void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat,
{ {
RECT sourceRect; RECT sourceRect;
sourceRect.left = x; sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width; sourceRect.right = x + width;
sourceRect.bottom = y; sourceRect.top = source->getHeight() - (y + height);
sourceRect.bottom = source->getHeight() - y;
IDirect3DSurface9 *dest = getCubeMapSurface(face, level); IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
...@@ -1251,9 +1295,9 @@ void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint ...@@ -1251,9 +1295,9 @@ void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint
RECT sourceRect; RECT sourceRect;
sourceRect.left = x; sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width; sourceRect.right = x + width;
sourceRect.bottom = y; sourceRect.top = source->getHeight() - (y + height);
sourceRect.bottom = source->getHeight() - y;
IDirect3DSurface9 *dest = getCubeMapSurface(face, level); IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
...@@ -1261,4 +1305,70 @@ void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint ...@@ -1261,4 +1305,70 @@ void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint
dest->Release(); 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;
}
}
getRenderTarget();
for (unsigned int f = 0; f < 6; f++)
{
for (unsigned int i = 1; i <= q; i++)
{
IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
if (upper != NULL && lower != NULL)
{
getBlitter()->boxFilter(upper, lower);
}
if (upper != NULL) upper->Release();
if (lower != NULL) lower->Release();
}
}
}
} }
...@@ -57,6 +57,8 @@ class Texture : public Colorbuffer ...@@ -57,6 +57,8 @@ class Texture : public Colorbuffer
IDirect3DSurface9 *getRenderTarget(GLenum target); IDirect3DSurface9 *getRenderTarget(GLenum target);
IDirect3DSurface9 *getRenderTarget() { return getRenderTarget(GL_TEXTURE_2D); } // FIXME: to be removed once FBO rendering is completed. IDirect3DSurface9 *getRenderTarget() { return getRenderTarget(GL_TEXTURE_2D); } // FIXME: to be removed once FBO rendering is completed.
virtual void generateMipmaps() = 0;
protected: protected:
// Helper structure representing a single image layer // Helper structure representing a single image layer
struct Image struct Image
...@@ -128,6 +130,8 @@ class Texture2D : public Texture ...@@ -128,6 +130,8 @@ class Texture2D : public Texture
bool isComplete() const; bool isComplete() const;
virtual void generateMipmaps();
private: private:
DISALLOW_COPY_AND_ASSIGN(Texture2D); DISALLOW_COPY_AND_ASSIGN(Texture2D);
...@@ -169,6 +173,8 @@ class TextureCubeMap : public Texture ...@@ -169,6 +173,8 @@ class TextureCubeMap : public Texture
bool isComplete() const; bool isComplete() const;
virtual void generateMipmaps();
private: private:
DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); DISALLOW_COPY_AND_ASSIGN(TextureCubeMap);
...@@ -185,6 +191,8 @@ class TextureCubeMap : public Texture ...@@ -185,6 +191,8 @@ class TextureCubeMap : public Texture
static unsigned int faceIndex(GLenum face); static unsigned int faceIndex(GLenum face);
bool isCubeComplete() const;
void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width); bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width);
......
...@@ -1751,7 +1751,28 @@ void __stdcall glGenerateMipmap(GLenum target) ...@@ -1751,7 +1751,28 @@ void __stdcall glGenerateMipmap(GLenum target)
try try
{ {
UNIMPLEMENTED(); // FIXME gl::Context *context = gl::getContext();
if (context)
{
gl::Texture *texture;
switch (target)
{
case GL_TEXTURE_2D:
texture = context->getTexture2D();
break;
case GL_TEXTURE_CUBE_MAP:
texture = context->getTextureCubeMap();
break;
default:
return error(GL_INVALID_ENUM);
}
texture->generateMipmaps();
}
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment