Implement CopyTex(Sub)Image2D

TRAC #11474 Signed-off-by: Shannon Woods Signed-off-by: Daniel Koch Author: Andrew Lewycky git-svn-id: https://angleproject.googlecode.com/svn/trunk@132 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 98079839
...@@ -158,6 +158,8 @@ ...@@ -158,6 +158,8 @@
'libGLESv2/geometry/vertexconversion.h', 'libGLESv2/geometry/vertexconversion.h',
'libGLESv2/geometry/VertexDataManager.cpp', 'libGLESv2/geometry/VertexDataManager.cpp',
'libGLESv2/geometry/VertexDataManager.h', 'libGLESv2/geometry/VertexDataManager.h',
'libGLESv2/Blit.cpp',
'libGLESv2/Blit.h',
'libGLESv2/Buffer.cpp', 'libGLESv2/Buffer.cpp',
'libGLESv2/Buffer.h', 'libGLESv2/Buffer.h',
'libGLESv2/Context.cpp', 'libGLESv2/Context.cpp',
......
//
// 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.
//
// Blit.cpp: Surface copy utility class.
#include "Blit.h"
#include <d3dx9.h>
#include "main.h"
#include "common/debug.h"
namespace
{
// Standard Vertex Shader
// Input 0 is the homogenous position.
// Outputs the homogenous position as-is.
// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right.
// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0.
const char standardvs[] =
"struct VS_OUTPUT\n"
"{\n"
" float4 position : POSITION;\n"
" float4 texcoord : TEXCOORD0;\n"
"};\n"
"\n"
"uniform float4 halfPixelSize : c0;\n"
"\n"
"VS_OUTPUT main(in float4 position : POSITION)\n"
"{\n"
" VS_OUTPUT Out;\n"
"\n"
" Out.position = position + halfPixelSize;\n"
" Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);\n"
"\n"
" return Out;\n"
"}\n";
// Flip Y Vertex Shader
// Input 0 is the homogenous position.
// Outputs the homogenous position as-is.
// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right.
// C0.XY must be the half-pixel width and height. C0.ZW must be 0.
const char flipyvs[] =
"struct VS_OUTPUT\n"
"{\n"
" float4 position : POSITION;\n"
" float4 texcoord : TEXCOORD0;\n"
"};\n"
"\n"
"uniform float4 halfPixelSize : c0;\n"
"\n"
"VS_OUTPUT main(in float4 position : POSITION)\n"
"{\n"
" VS_OUTPUT Out;\n"
"\n"
" Out.position = position + halfPixelSize;\n"
" Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);\n"
"\n"
" return Out;\n"
"}\n";
// Passthrough Pixel Shader
// Outputs texture 0 sampled at texcoord 0.
const char passthroughps[] =
"sampler2D tex : s0;\n"
"\n"
"float4 main(float4 texcoord : TEXCOORD0) : COLOR\n"
"{\n"
" return tex2D(tex, texcoord.xy);\n"
"}\n";
// Luminance Conversion Pixel Shader
// Outputs sample(tex0, tc0).rrra.
// For LA output (pass A) set C0.X = 1, C0.Y = 0.
// For L output (A = 1) set C0.X = 0, C0.Y = 1.
const char luminanceps[] =
"sampler2D tex : s0;\n"
"\n"
"uniform float4 mode : c0;\n"
"\n"
"float4 main(float4 texcoord : TEXCOORD0) : COLOR\n"
"{\n"
" float4 tmp = tex2D(tex, texcoord.xy);\n"
" tmp.w = tmp.w * mode.x + mode.y;\n"
" return tmp.xxxw;\n"
"}\n";
// RGB/A Component Mask Pixel Shader
// Outputs sample(tex0, tc0) with options to force RGB = 0 and/or A = 1.
// To force RGB = 0, set C0.X = 0, otherwise C0.X = 1.
// To force A = 1, set C0.Z = 0, C0.W = 1, otherwise C0.Z = 1, C0.W = 0.
const char componentmaskps[] =
"sampler2D tex : s0;\n"
"\n"
"uniform float4 mode : c0;\n"
"\n"
"float4 main(float4 texcoord : TEXCOORD0) : COLOR\n"
"{\n"
" float4 tmp = tex2D(tex, texcoord.xy);\n"
" tmp.xyz = tmp.xyz * mode.x;\n"
" tmp.w = tmp.w * mode.z + mode.w;\n"
" return tmp;\n"
"}\n";
}
namespace gl
{
const char * const Blit::mShaderSource[] =
{
standardvs,
flipyvs,
passthroughps,
luminanceps,
componentmaskps
};
Blit::Blit(Context *context)
: mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL)
{
initGeometry();
memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
}
Blit::~Blit()
{
if (mQuadVertexBuffer) mQuadVertexBuffer->Release();
if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release();
for (int i = 0; i < SHADER_COUNT; i++)
{
if (mCompiledShaders[i])
{
mCompiledShaders[i]->Release();
}
}
}
void Blit::initGeometry()
{
static const float quad[] =
{
-1, -1,
-1, 1,
1, -1,
1, 1
};
IDirect3DDevice9 *device = getDevice();
HRESULT hr = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
if (FAILED(hr))
{
ASSERT(hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
return error(GL_OUT_OF_MEMORY);
}
void *lockPtr;
mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
memcpy(lockPtr, quad, sizeof(quad));
mQuadVertexBuffer->Unlock();
static const D3DVERTEXELEMENT9 elements[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
D3DDECL_END()
};
hr = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
if (FAILED(hr))
{
ASSERT(hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
return error(GL_OUT_OF_MEMORY);
}
}
template <class D3DShaderType>
bool Blit::setShader(ShaderId source, const char *profile,
HRESULT (WINAPI IDirect3DDevice9::*createShader)(const DWORD *, D3DShaderType**),
HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
{
IDirect3DDevice9 *device = getDevice();
D3DShaderType *shader;
if (mCompiledShaders[source] != NULL)
{
shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
}
else
{
ID3DXBuffer *shaderCode;
HRESULT hr = D3DXCompileShader(mShaderSource[source], strlen(mShaderSource[source]), NULL, NULL, "main", profile, 0, &shaderCode, NULL, NULL);
if (FAILED(hr))
{
ERR("Failed to compile %s shader for blit operation %d, error 0x%08X.", profile, (int)source, hr);
return false;
}
hr = (device->*createShader)(static_cast<const DWORD*>(shaderCode->GetBufferPointer()), &shader);
if (FAILED(hr))
{
shaderCode->Release();
ERR("Failed to create %s shader for blit operation %d, error 0x%08X.", profile, (int)source, hr);
return false;
}
shaderCode->Release();
mCompiledShaders[source] = shader;
}
HRESULT hr = (device->*setShader)(shader);
if (FAILED(hr))
{
ERR("Failed to set %s shader for blit operation %d, error 0x%08X.", profile, (int)source, hr);
return false;
}
return true;
}
bool Blit::setVertexShader(ShaderId shader)
{
return setShader<IDirect3DVertexShader9>(shader, mContext->getVertexShaderProfile(), &IDirect3DDevice9::CreateVertexShader, &IDirect3DDevice9::SetVertexShader);
}
bool Blit::setPixelShader(ShaderId shader)
{
return setShader<IDirect3DPixelShader9>(shader, mContext->getPixelShaderProfile(), &IDirect3DDevice9::CreatePixelShader, &IDirect3DDevice9::SetPixelShader);
}
bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
{
IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
if (!texture)
{
return false;
}
IDirect3DDevice9 *device = getDevice();
device->SetTexture(0, texture);
device->SetRenderTarget(0, dest);
setViewport(sourceRect, xoffset, yoffset, dest);
setCommonBlitState();
if (setFormatConvertShaders(destFormat))
{
render();
}
texture->Release();
return true;
}
bool Blit::setFormatConvertShaders(GLenum destFormat)
{
bool okay = setVertexShader(SHADER_VS_STANDARD);
switch (destFormat)
{
default: UNREACHABLE();
case GL_RGBA:
case GL_RGB:
case GL_ALPHA:
okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
break;
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
break;
}
if (!okay)
{
return false;
}
enum { X = 0, Y = 1, Z = 2, W = 3 };
// The meaning of this constant depends on the shader that was selected.
// See the shader assembly code above for details.
float psConst0[4] = { 0, 0, 0, 0 };
switch (destFormat)
{
default: UNREACHABLE();
case GL_RGBA:
psConst0[X] = 1;
psConst0[Z] = 1;
break;
case GL_RGB:
psConst0[X] = 1;
psConst0[W] = 1;
break;
case GL_ALPHA:
psConst0[Z] = 1;
break;
case GL_LUMINANCE:
psConst0[Y] = 1;
break;
case GL_LUMINANCE_ALPHA:
psConst0[X] = 1;
break;
}
getDevice()->SetPixelShaderConstantF(0, psConst0, 1);
return true;
}
IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
{
IDirect3DDevice9 *device = getDevice();
D3DSURFACE_DESC sourceDesc;
surface->GetDesc(&sourceDesc);
// Copy the render target into a texture
IDirect3DTexture9 *texture;
HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.top - sourceRect.bottom, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
if (FAILED(result))
{
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
}
IDirect3DSurface9 *textureSurface;
result = texture->GetSurfaceLevel(0, &textureSurface);
if (FAILED(result))
{
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
texture->Release();
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
}
RECT d3dSourceRect;
d3dSourceRect.left = sourceRect.left;
d3dSourceRect.right = sourceRect.right;
d3dSourceRect.top = sourceRect.bottom;
d3dSourceRect.bottom = sourceRect.top;
result = device->StretchRect(surface, &d3dSourceRect, textureSurface, NULL, D3DTEXF_NONE);
textureSurface->Release();
if (FAILED(result))
{
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
texture->Release();
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
}
return texture;
}
void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
{
D3DSURFACE_DESC desc;
dest->GetDesc(&desc);
IDirect3DDevice9 *device = getDevice();
D3DVIEWPORT9 vp;
vp.X = xoffset;
vp.Y = yoffset;
vp.Width = sourceRect.right - sourceRect.left;
vp.Height = sourceRect.top - sourceRect.bottom;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
device->SetViewport(&vp);
float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
}
void Blit::setCommonBlitState()
{
IDirect3DDevice9 *device = getDevice();
device->SetDepthStencilSurface(NULL);
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
}
void Blit::render()
{
IDirect3DDevice9 *device = getDevice();
HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
device->BeginScene();
hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device->EndScene();
}
}
//
// 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.
//
// Blit.cpp: Surface copy utility class.
#ifndef LIBGLESV2_BLIT_H_
#define LIBGLESV2_BLIT_H_
#include <map>
#define GL_APICALL
#include <GLES2/gl2.h>
#include <d3d9.h>
#include "common/angleutils.h"
namespace gl
{
class Context;
class Blit
{
public:
explicit Blit(Context *context);
~Blit();
// 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).
// 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);
private:
Context *mContext;
IDirect3DVertexBuffer9 *mQuadVertexBuffer;
IDirect3DVertexDeclaration9 *mQuadVertexDeclaration;
void initGeometry();
bool setFormatConvertShaders(GLenum destFormat);
IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect);
void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest);
void setCommonBlitState();
// This enum is used to index mCompiledShaders and mShaderSource.
enum ShaderId
{
SHADER_VS_STANDARD,
SHADER_VS_FLIPY,
SHADER_PS_PASSTHROUGH,
SHADER_PS_LUMINANCE,
SHADER_PS_COMPONENTMASK,
SHADER_COUNT
};
static const char * const mShaderSource[];
// This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown.
IUnknown *mCompiledShaders[SHADER_COUNT];
template <class D3DShaderType>
bool setShader(ShaderId source, const char *profile,
HRESULT (WINAPI IDirect3DDevice9::*createShader)(const DWORD *, D3DShaderType **),
HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*));
bool setVertexShader(ShaderId shader);
bool setPixelShader(ShaderId shader);
void render();
DISALLOW_COPY_AND_ASSIGN(Blit);
};
}
#endif // LIBGLESV2_BLIT_H_
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "geometry/VertexDataManager.h" #include "geometry/VertexDataManager.h"
#include "geometry/IndexDataManager.h" #include "geometry/IndexDataManager.h"
#include "geometry/dx9.h" #include "geometry/dx9.h"
#include "Blit.h"
#undef near #undef near
#undef far #undef far
...@@ -106,8 +107,8 @@ Context::Context(const egl::Config *config) ...@@ -106,8 +107,8 @@ Context::Context(const egl::Config *config)
// In order that access to these initial textures not be lost, they are treated as texture // In order that access to these initial textures not be lost, they are treated as texture
// objects all of whose names are 0. // objects all of whose names are 0.
mTexture2DZero = new Texture2D(); mTexture2DZero = new Texture2D(this);
mTextureCubeMapZero = new TextureCubeMap(); mTextureCubeMapZero = new TextureCubeMap(this);
mColorbufferZero = NULL; mColorbufferZero = NULL;
mDepthbufferZero = NULL; mDepthbufferZero = NULL;
...@@ -142,6 +143,7 @@ Context::Context(const egl::Config *config) ...@@ -142,6 +143,7 @@ Context::Context(const egl::Config *config)
mBufferBackEnd = NULL; mBufferBackEnd = NULL;
mVertexDataManager = NULL; mVertexDataManager = NULL;
mIndexDataManager = NULL; mIndexDataManager = NULL;
mBlit = NULL;
mInvalidEnum = false; mInvalidEnum = false;
mInvalidValue = false; mInvalidValue = false;
...@@ -171,6 +173,7 @@ Context::~Context() ...@@ -171,6 +173,7 @@ Context::~Context()
delete mBufferBackEnd; delete mBufferBackEnd;
delete mVertexDataManager; delete mVertexDataManager;
delete mIndexDataManager; delete mIndexDataManager;
delete mBlit;
while (!mBufferMap.empty()) while (!mBufferMap.empty())
{ {
...@@ -212,6 +215,7 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) ...@@ -212,6 +215,7 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
mBufferBackEnd = new Dx9BackEnd(device); mBufferBackEnd = new Dx9BackEnd(device);
mVertexDataManager = new VertexDataManager(this, mBufferBackEnd); mVertexDataManager = new VertexDataManager(this, mBufferBackEnd);
mIndexDataManager = new IndexDataManager(this, mBufferBackEnd); mIndexDataManager = new IndexDataManager(this, mBufferBackEnd);
mBlit = new Blit(this);
} }
// Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names
...@@ -501,7 +505,7 @@ void Context::bindTexture2D(GLuint texture) ...@@ -501,7 +505,7 @@ void Context::bindTexture2D(GLuint texture)
{ {
if (!getTexture(texture) && texture != 0) if (!getTexture(texture) && texture != 0)
{ {
mTextureMap[texture] = new Texture2D(); mTextureMap[texture] = new Texture2D(this);
} }
texture2D = texture; texture2D = texture;
...@@ -513,7 +517,7 @@ void Context::bindTextureCubeMap(GLuint texture) ...@@ -513,7 +517,7 @@ void Context::bindTextureCubeMap(GLuint texture)
{ {
if (!getTexture(texture) && texture != 0) if (!getTexture(texture) && texture != 0)
{ {
mTextureMap[texture] = new TextureCubeMap(); mTextureMap[texture] = new TextureCubeMap(this);
} }
textureCubeMap = texture; textureCubeMap = texture;
...@@ -2157,7 +2161,7 @@ Texture *Context::getIncompleteTexture(SamplerType type) ...@@ -2157,7 +2161,7 @@ Texture *Context::getIncompleteTexture(SamplerType type)
case SAMPLER_2D: case SAMPLER_2D:
{ {
Texture2D *incomplete2d = new Texture2D; Texture2D *incomplete2d = new Texture2D(this);
incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
t = incomplete2d; t = incomplete2d;
} }
...@@ -2165,7 +2169,7 @@ Texture *Context::getIncompleteTexture(SamplerType type) ...@@ -2165,7 +2169,7 @@ Texture *Context::getIncompleteTexture(SamplerType type)
case SAMPLER_CUBE: case SAMPLER_CUBE:
{ {
TextureCubeMap *incompleteCube = new TextureCubeMap; TextureCubeMap *incompleteCube = new TextureCubeMap(this);
incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
......
...@@ -46,6 +46,7 @@ class Stencilbuffer; ...@@ -46,6 +46,7 @@ class Stencilbuffer;
class VertexDataManager; class VertexDataManager;
class IndexDataManager; class IndexDataManager;
class BufferBackEnd; class BufferBackEnd;
class Blit;
enum enum
{ {
...@@ -288,6 +289,8 @@ class Context : public State ...@@ -288,6 +289,8 @@ class Context : public State
const char *getPixelShaderProfile(); const char *getPixelShaderProfile();
const char *getVertexShaderProfile(); const char *getVertexShaderProfile();
Blit *getBlitter() { return mBlit; }
private: private:
DISALLOW_COPY_AND_ASSIGN(Context); DISALLOW_COPY_AND_ASSIGN(Context);
...@@ -334,6 +337,8 @@ class Context : public State ...@@ -334,6 +337,8 @@ class Context : public State
VertexDataManager *mVertexDataManager; VertexDataManager *mVertexDataManager;
IndexDataManager *mIndexDataManager; IndexDataManager *mIndexDataManager;
Blit *mBlit;
Texture *mIncompleteTextures[SAMPLER_TYPE_COUNT]; Texture *mIncompleteTextures[SAMPLER_TYPE_COUNT];
// Recorded errors // Recorded errors
......
...@@ -16,12 +16,13 @@ ...@@ -16,12 +16,13 @@
#include "mathutil.h" #include "mathutil.h"
#include "common/debug.h" #include "common/debug.h"
#include "utilities.h" #include "utilities.h"
#include "Blit.h"
namespace gl namespace gl
{ {
Texture::Image::Image() Texture::Image::Image()
: dirty(false), surface(NULL) : width(0), height(0), dirty(false), surface(NULL)
{ {
} }
...@@ -30,7 +31,7 @@ Texture::Image::~Image() ...@@ -30,7 +31,7 @@ Texture::Image::~Image()
if (surface) surface->Release(); if (surface) surface->Release();
} }
Texture::Texture() : Colorbuffer(0) Texture::Texture(Context *context) : Colorbuffer(0), mContext(context)
{ {
mMinFilter = GL_NEAREST_MIPMAP_LINEAR; mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
mMagFilter = GL_LINEAR; mMagFilter = GL_LINEAR;
...@@ -44,6 +45,11 @@ Texture::~Texture() ...@@ -44,6 +45,11 @@ Texture::~Texture()
{ {
} }
Blit *Texture::getBlitter()
{
return mContext->getBlitter();
}
// Returns true on successful filter state update (valid enum parameter) // Returns true on successful filter state update (valid enum parameter)
bool Texture::setMinFilter(GLenum filter) bool Texture::setMinFilter(GLenum filter)
{ {
...@@ -388,7 +394,28 @@ IDirect3DSurface9 *Texture::getRenderTarget(GLenum target) ...@@ -388,7 +394,28 @@ IDirect3DSurface9 *Texture::getRenderTarget(GLenum target)
return mRenderTarget; return mRenderTarget;
} }
Texture2D::Texture2D() void Texture::dropTexture()
{
if (mRenderTarget)
{
mRenderTarget->Release();
mRenderTarget = NULL;
}
if (mBaseTexture)
{
mBaseTexture = NULL;
}
}
void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture)
{
mBaseTexture = newTexture;
mDirtyMetaData = false;
}
Texture2D::Texture2D(Context *context) : Texture(context)
{ {
mTexture = NULL; mTexture = NULL;
} }
...@@ -407,15 +434,62 @@ GLenum Texture2D::getTarget() const ...@@ -407,15 +434,62 @@ GLenum Texture2D::getTarget() const
return GL_TEXTURE_2D; return GL_TEXTURE_2D;
} }
void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) // 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 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)
{ {
Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]); 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));
if (level == 0) bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
if (!textureOkay)
{ {
mWidth = width; TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
mHeight = height; mImageArray[0].format, mWidth, mHeight,
internalFormat, width, height);
// Purge all the levels and the texture.
for (int i = 0; i < 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;
} }
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);
Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
} }
void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
...@@ -459,6 +533,56 @@ void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei widt ...@@ -459,6 +533,56 @@ void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei widt
commitRect(level, xoffset, yoffset, width, height); commitRect(level, xoffset, yoffset, width, height);
} }
void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
{
if (redefineTexture(level, internalFormat, width, height))
{
convertToRenderTarget();
pushTexture(mTexture);
}
RECT sourceRect;
sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width;
sourceRect.bottom = y;
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(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
{
if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
{
convertToRenderTarget();
pushTexture(mTexture);
}
else
{
getRenderTarget(GL_TEXTURE_2D);
}
RECT sourceRect;
sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width;
sourceRect.bottom = y;
IDirect3DSurface9 *dest;
HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
dest->Release();
}
// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. // Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
bool Texture2D::isComplete() const bool Texture2D::isComplete() const
{ {
...@@ -654,7 +778,7 @@ bool Texture2D::dirtyImageData() const ...@@ -654,7 +778,7 @@ bool Texture2D::dirtyImageData() const
return false; return false;
} }
TextureCubeMap::TextureCubeMap() TextureCubeMap::TextureCubeMap(Context *context) : Texture(context)
{ {
mTexture = NULL; mTexture = NULL;
} }
...@@ -711,12 +835,10 @@ void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, G ...@@ -711,12 +835,10 @@ void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, G
if (mTexture != NULL) if (mTexture != NULL)
{ {
IDirect3DSurface9 *destLevel = NULL; IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
HRESULT result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(face), level, &destLevel); ASSERT(destLevel != NULL);
ASSERT(SUCCEEDED(result));
if (SUCCEEDED(result)) if (destLevel != NULL)
{ {
Image *img = &mImageArray[face][level]; Image *img = &mImageArray[face][level];
...@@ -730,7 +852,7 @@ void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, G ...@@ -730,7 +852,7 @@ void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, G
destPoint.x = xoffset; destPoint.x = xoffset;
destPoint.y = yoffset; destPoint.y = yoffset;
result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint); HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
destLevel->Release(); destLevel->Release();
...@@ -842,14 +964,12 @@ void TextureCubeMap::updateTexture() ...@@ -842,14 +964,12 @@ void TextureCubeMap::updateTexture()
if (img->dirty) if (img->dirty)
{ {
IDirect3DSurface9 *levelSurface; IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
HRESULT result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(face), level, &levelSurface); ASSERT(levelSurface != NULL);
ASSERT(SUCCEEDED(result));
if (SUCCEEDED(result)) if (levelSurface != NULL)
{ {
result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL); HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
levelSurface->Release(); levelSurface->Release();
...@@ -934,21 +1054,16 @@ IDirect3DSurface9 *TextureCubeMap::getSurface(GLenum target) ...@@ -934,21 +1054,16 @@ IDirect3DSurface9 *TextureCubeMap::getSurface(GLenum target)
{ {
ASSERT(es2dx::IsCubemapTextureTarget(target)); ASSERT(es2dx::IsCubemapTextureTarget(target));
IDirect3DSurface9 *surface = NULL; IDirect3DSurface9 *surface = getCubeMapSurface(target, 0);
HRESULT result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &surface); ASSERT(surface != NULL);
ASSERT(SUCCEEDED(result));
return surface; return surface;
} }
void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
{ {
Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]); redefineTexture(level, internalFormat, width);
if (face == 0 && level == 0) Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
{
mWidth = width;
mHeight = height;
}
} }
unsigned int TextureCubeMap::faceIndex(GLenum face) unsigned int TextureCubeMap::faceIndex(GLenum face)
...@@ -977,4 +1092,137 @@ bool TextureCubeMap::dirtyImageData() const ...@@ -977,4 +1092,137 @@ bool TextureCubeMap::dirtyImageData() const
return false; 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 < 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 face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
{
unsigned int faceindex = faceIndex(face);
if (redefineTexture(level, internalFormat, width))
{
convertToRenderTarget();
pushTexture(mTexture);
}
RECT sourceRect;
sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width;
sourceRect.bottom = y;
IDirect3DSurface9 *dest = getCubeMapSurface(face, 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(unsigned int faceIdentifier, unsigned int level)
{
unsigned int faceIndex;
if (faceIdentifier < 6)
{
faceIndex = faceIdentifier;
}
else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
{
faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
}
else
{
UNREACHABLE();
faceIndex = 0;
}
if (mTexture == NULL)
{
UNREACHABLE();
return NULL;
}
IDirect3DSurface9 *surface = NULL;
HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
return (SUCCEEDED(hr)) ? surface : NULL;
}
void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
{
if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
{
convertToRenderTarget();
pushTexture(mTexture);
}
else
{
getRenderTarget(face);
}
RECT sourceRect;
sourceRect.left = x;
sourceRect.top = y + height;
sourceRect.right = x + width;
sourceRect.bottom = y;
IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
dest->Release();
}
} }
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
namespace gl namespace gl
{ {
class Context;
class Blit;
enum enum
{ {
MAX_TEXTURE_SIZE = 2048, MAX_TEXTURE_SIZE = 2048,
...@@ -32,7 +35,7 @@ enum ...@@ -32,7 +35,7 @@ enum
class Texture : public Colorbuffer class Texture : public Colorbuffer
{ {
public: public:
Texture(); explicit Texture(Context *context);
~Texture(); ~Texture();
...@@ -90,11 +93,17 @@ class Texture : public Colorbuffer ...@@ -90,11 +93,17 @@ class Texture : public Colorbuffer
virtual bool dirtyImageData() const = 0; virtual bool dirtyImageData() const = 0;
void dropTexture();
void pushTexture(IDirect3DBaseTexture9 *newTexture);
Blit *getBlitter();
private: private:
DISALLOW_COPY_AND_ASSIGN(Texture); DISALLOW_COPY_AND_ASSIGN(Texture);
IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer. Context *mContext;
IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer.
bool mDirtyMetaData; bool mDirtyMetaData;
void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
...@@ -106,7 +115,7 @@ class Texture : public Colorbuffer ...@@ -106,7 +115,7 @@ class Texture : public Colorbuffer
class Texture2D : public Texture class Texture2D : public Texture
{ {
public: public:
Texture2D(); explicit Texture2D(Context *context);
~Texture2D(); ~Texture2D();
...@@ -114,6 +123,8 @@ class Texture2D : public Texture ...@@ -114,6 +123,8 @@ class Texture2D : public Texture
void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
void copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
bool isComplete() const; bool isComplete() const;
...@@ -132,12 +143,14 @@ class Texture2D : public Texture ...@@ -132,12 +143,14 @@ class Texture2D : public Texture
Image mImageArray[MAX_TEXTURE_LEVELS]; Image mImageArray[MAX_TEXTURE_LEVELS];
IDirect3DTexture9 *mTexture; IDirect3DTexture9 *mTexture;
bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height);
}; };
class TextureCubeMap : public Texture class TextureCubeMap : public Texture
{ {
public: public:
TextureCubeMap(); explicit TextureCubeMap(Context *context);
~TextureCubeMap(); ~TextureCubeMap();
...@@ -151,6 +164,8 @@ class TextureCubeMap : public Texture ...@@ -151,6 +164,8 @@ class TextureCubeMap : public Texture
void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
void copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
bool isComplete() const; bool isComplete() const;
...@@ -164,10 +179,15 @@ class TextureCubeMap : public Texture ...@@ -164,10 +179,15 @@ class TextureCubeMap : public Texture
virtual bool dirtyImageData() const; virtual bool dirtyImageData() const;
// faceIdentifier is 0-5 or one of the GL_TEXTURE_CUBE_MAP_* enumerants.
// Returns NULL if the call underlying Direct3D call fails.
IDirect3DSurface9 *getCubeMapSurface(unsigned int faceIdentifier, unsigned int level);
static unsigned int faceIndex(GLenum face); static unsigned int faceIndex(GLenum face);
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);
Image mImageArray[6][MAX_TEXTURE_LEVELS]; Image mImageArray[6][MAX_TEXTURE_LEVELS];
......
...@@ -791,12 +791,94 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma ...@@ -791,12 +791,94 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma
try try
{ {
if (width < 0 || height < 0) if (level < 0 || width < 0 || height < 0)
{ {
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
UNIMPLEMENTED(); // FIXME if (level > 0 && (!gl::isPow2(width) || !gl::isPow2(height)))
{
return error(GL_INVALID_VALUE);
}
switch (target)
{
case GL_TEXTURE_2D:
if (width > (gl::MAX_TEXTURE_SIZE >> level) || height > (gl::MAX_TEXTURE_SIZE >> level))
{
return error(GL_INVALID_VALUE);
}
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
if (!gl::isPow2(width) || !gl::isPow2(height))
{
return error(GL_INVALID_VALUE);
}
if (width > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level) || height > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level))
{
return error(GL_INVALID_VALUE);
}
break;
default:
return error(GL_INVALID_ENUM);
}
switch (internalformat)
{
case GL_ALPHA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case GL_RGB:
case GL_RGBA:
break;
default:
return error(GL_INVALID_VALUE);
}
if (border != 0)
{
return error(GL_INVALID_VALUE);
}
gl::Context *context = gl::getContext();
if (context)
{
gl::Renderbuffer *source = context->getFramebuffer()->getColorbuffer();
if (target == GL_TEXTURE_2D)
{
gl::Texture2D *texture = context->getTexture2D();
if (!texture)
{
return error(GL_INVALID_OPERATION);
}
texture->copyImage(level, internalformat, x, y, width, height, source);
}
else if (es2dx::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (!texture)
{
return error(GL_INVALID_OPERATION);
}
texture->copyImage(target, level, internalformat, x, y, width, height, source);
}
else
{
UNREACHABLE();
}
}
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
{ {
...@@ -812,13 +894,61 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL ...@@ -812,13 +894,61 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL
try try
{ {
if (width < 0 || height < 0) if (target != GL_TEXTURE_2D && !es2dx::IsCubemapTextureTarget(target))
{
return error(GL_INVALID_ENUM);
}
if (level < 0 || level > gl::MAX_TEXTURE_LEVELS || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
{ {
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
UNIMPLEMENTED(); // FIXME if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return error(GL_INVALID_VALUE);
}
if (width == 0 || height == 0)
{
return;
}
gl::Context *context = gl::getContext();
if (context)
{
gl::Renderbuffer *source = context->getFramebuffer()->getColorbuffer();
if (target == GL_TEXTURE_2D)
{
gl::Texture2D *texture = context->getTexture2D();
if (!texture)
{
return error(GL_INVALID_OPERATION);
}
texture->copySubImage(level, xoffset, yoffset, x, y, width, height, source);
}
else if (es2dx::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (!texture)
{
return error(GL_INVALID_OPERATION);
}
texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, source);
}
else
{
UNREACHABLE();
}
}
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
{ {
return error(GL_OUT_OF_MEMORY); return error(GL_OUT_OF_MEMORY);
......
...@@ -181,6 +181,10 @@ ...@@ -181,6 +181,10 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File <File
RelativePath=".\Blit.cpp"
>
</File>
<File
RelativePath=".\Buffer.cpp" RelativePath=".\Buffer.cpp"
> >
</File> </File>
...@@ -251,6 +255,10 @@ ...@@ -251,6 +255,10 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File <File
RelativePath=".\Blit.h"
>
</File>
<File
RelativePath=".\Buffer.h" RelativePath=".\Buffer.h"
> >
</File> </File>
......
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