2 // Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
7 // TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived
8 // classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
11 #include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h"
12 #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h"
13 #include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h"
14 #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h"
15 #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h"
16 #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h"
17 #include "libGLESv2/renderer/d3d/TextureD3D.h"
18 #include "libGLESv2/Texture.h"
19 #include "libGLESv2/main.h"
23 TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage)
28 mTextureFormat(D3DFMT_UNKNOWN),
29 mRenderer(Renderer9::makeRenderer9(renderer)),
31 mD3DPool(mRenderer->getTexturePool(usage))
35 TextureStorage9::~TextureStorage9()
39 TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage)
41 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage));
42 return static_cast<TextureStorage9*>(storage);
45 DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget)
49 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
50 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
51 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
53 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
55 else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN))
57 d3dusage |= D3DUSAGE_RENDERTARGET;
64 bool TextureStorage9::isRenderTarget() const
66 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
69 bool TextureStorage9::isManaged() const
71 return (mD3DPool == D3DPOOL_MANAGED);
74 D3DPOOL TextureStorage9::getPool() const
79 DWORD TextureStorage9::getUsage() const
84 int TextureStorage9::getTopLevel() const
89 int TextureStorage9::getLevelCount() const
91 return mMipLevels - mTopLevel;
94 gl::Error TextureStorage9::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type,
95 const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
98 return gl::Error(GL_INVALID_OPERATION);
101 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain)
102 : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
104 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
105 mTexture = surfaceTexture;
106 mMipLevels = surfaceTexture->GetLevelCount();
108 D3DSURFACE_DESC surfaceDesc;
109 surfaceTexture->GetLevelDesc(0, &surfaceDesc);
110 mTextureWidth = surfaceDesc.Width;
111 mTextureHeight = surfaceDesc.Height;
112 mTextureFormat = surfaceDesc.Format;
114 mRenderTarget = NULL;
116 initializeSerials(1, 1);
119 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels)
120 : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
123 mRenderTarget = NULL;
125 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
126 mTextureFormat = d3dFormatInfo.texFormat;
128 d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel);
129 mTextureWidth = width;
130 mTextureHeight = height;
131 mMipLevels = mTopLevel + levels;
133 initializeSerials(getLevelCount(), 1);
136 TextureStorage9_2D::~TextureStorage9_2D()
138 SafeRelease(mTexture);
139 SafeDelete(mRenderTarget);
142 TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage)
144 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage));
145 return static_cast<TextureStorage9_2D*>(storage);
148 // Increments refcount on surface.
149 // caller must Release() the returned surface
150 gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface)
152 IDirect3DBaseTexture9 *baseTexture = NULL;
153 gl::Error error = getBaseTexture(&baseTexture);
159 IDirect3DTexture9 *texture = static_cast<IDirect3DTexture9*>(baseTexture);
161 HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface);
163 ASSERT(SUCCEEDED(result));
166 return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result);
169 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
170 if (level + mTopLevel != 0 && isManaged() && dirty)
172 texture->AddDirtyRect(NULL);
175 return gl::Error(GL_NO_ERROR);
178 gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/, RenderTarget **outRT)
180 if (!mRenderTarget && isRenderTarget())
182 IDirect3DSurface9 *surface = NULL;
183 gl::Error error = getSurfaceLevel(0, false, &surface);
189 mRenderTarget = new RenderTarget9(mRenderer, surface);
193 *outRT = mRenderTarget;
194 return gl::Error(GL_NO_ERROR);
197 gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
199 IDirect3DSurface9 *upper = NULL;
200 gl::Error error = getSurfaceLevel(sourceIndex.mipIndex, false, &upper);
206 IDirect3DSurface9 *lower = NULL;
207 error = getSurfaceLevel(destIndex.mipIndex, true, &lower);
214 ASSERT(upper && lower);
215 error = mRenderer->boxFilter(upper, lower);
223 gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
225 // if the width or height is not positive this should be treated as an incomplete texture
226 // we handle that here by skipping the d3d texture creation
227 if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
229 ASSERT(mMipLevels > 0);
231 IDirect3DDevice9 *device = mRenderer->getDevice();
232 HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat,
233 getPool(), &mTexture, NULL);
237 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
238 return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result);
242 *outTexture = mTexture;
243 return gl::Error(GL_NO_ERROR);
246 gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage)
250 TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(destStorage);
252 int levels = getLevelCount();
253 for (int i = 0; i < levels; ++i)
255 IDirect3DSurface9 *srcSurf = NULL;
256 gl::Error error = getSurfaceLevel(i, false, &srcSurf);
262 IDirect3DSurface9 *dstSurf = NULL;
263 error = dest9->getSurfaceLevel(i, true, &dstSurf);
266 SafeRelease(srcSurf);
270 error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged());
272 SafeRelease(srcSurf);
273 SafeRelease(dstSurf);
281 return gl::Error(GL_NO_ERROR);
284 TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels)
285 : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
288 for (int i = 0; i < CUBE_FACE_COUNT; ++i)
290 mRenderTarget[i] = NULL;
293 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
294 mTextureFormat = d3dFormatInfo.texFormat;
297 d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel);
298 mTextureWidth = size;
299 mTextureHeight = size;
300 mMipLevels = mTopLevel + levels;
302 initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT);
305 TextureStorage9_Cube::~TextureStorage9_Cube()
307 SafeRelease(mTexture);
309 for (int i = 0; i < CUBE_FACE_COUNT; ++i)
311 SafeDelete(mRenderTarget[i]);
315 TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage)
317 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage));
318 return static_cast<TextureStorage9_Cube*>(storage);
321 // Increments refcount on surface.
322 // caller must Release() the returned surface
323 gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface)
325 IDirect3DBaseTexture9 *baseTexture = NULL;
326 gl::Error error = getBaseTexture(&baseTexture);
332 IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9*>(baseTexture);
334 D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
335 HRESULT result = texture->GetCubeMapSurface(face, level + mTopLevel, outSurface);
337 ASSERT(SUCCEEDED(result));
340 return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result);
343 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
344 if (level != 0 && isManaged() && dirty)
346 texture->AddDirtyRect(face, NULL);
349 return gl::Error(GL_NO_ERROR);
352 gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
355 ASSERT(index.mipIndex == 0);
356 ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT);
358 if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget())
360 IDirect3DSurface9 *surface = NULL;
361 gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, 0, false, &surface);
367 mRenderTarget[index.layerIndex] = new RenderTarget9(mRenderer, surface);
370 *outRT = mRenderTarget[index.layerIndex];
371 return gl::Error(GL_NO_ERROR);
374 gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
376 IDirect3DSurface9 *upper = NULL;
377 gl::Error error = getCubeMapSurface(sourceIndex.type, sourceIndex.mipIndex, false, &upper);
383 IDirect3DSurface9 *lower = NULL;
384 error = getCubeMapSurface(destIndex.type, destIndex.mipIndex, true, &lower);
391 ASSERT(upper && lower);
392 error = mRenderer->boxFilter(upper, lower);
400 gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
402 // if the size is not positive this should be treated as an incomplete texture
403 // we handle that here by skipping the d3d texture creation
404 if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
406 ASSERT(mMipLevels > 0);
407 ASSERT(mTextureWidth == mTextureHeight);
409 IDirect3DDevice9 *device = mRenderer->getDevice();
410 HRESULT result = device->CreateCubeTexture(mTextureWidth, mMipLevels, getUsage(), mTextureFormat, getPool(),
415 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
416 return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result);
420 *outTexture = mTexture;
421 return gl::Error(GL_NO_ERROR);
424 gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage)
428 TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(destStorage);
430 int levels = getLevelCount();
431 for (int f = 0; f < CUBE_FACE_COUNT; f++)
433 for (int i = 0; i < levels; i++)
435 IDirect3DSurface9 *srcSurf = NULL;
436 gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf);
442 IDirect3DSurface9 *dstSurf = NULL;
443 error = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf);
446 SafeRelease(srcSurf);
450 error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged());
452 SafeRelease(srcSurf);
453 SafeRelease(dstSurf);
462 return gl::Error(GL_NO_ERROR);