blob: a8efca7fb4ba7ffcd4347b4f79d191e15d293a4d [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com34da3972012-12-20 21:10:29 +00002//
Nicolas Capens930f05e2013-06-18 15:31:58 -04003// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com34da3972012-12-20 21:10:29 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived
daniel@transgaming.com87705f82012-12-20 21:10:45 +00009// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
daniel@transgaming.com34da3972012-12-20 21:10:29 +000010// D3D9 texture.
11
12#include "libGLESv2/main.h"
Geoff Langd47e0fc2013-08-29 11:40:43 -040013#include "libGLESv2/renderer/d3d9/Renderer9.h"
14#include "libGLESv2/renderer/d3d9/TextureStorage9.h"
15#include "libGLESv2/renderer/d3d9/SwapChain9.h"
16#include "libGLESv2/renderer/d3d9/RenderTarget9.h"
17#include "libGLESv2/renderer/d3d9/renderer9_utils.h"
18#include "libGLESv2/renderer/d3d9/formatutils9.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000019#include "libGLESv2/Texture.h"
daniel@transgaming.com34da3972012-12-20 21:10:29 +000020
daniel@transgaming.com34da3972012-12-20 21:10:29 +000021namespace rx
22{
Nicolas Capensfa7b76d2014-03-31 14:51:45 -040023TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage)
Nicolas Capensf61738a2014-03-31 14:50:18 -040024 : mTopLevel(0),
daniel@transgaming.com34da3972012-12-20 21:10:29 +000025 mRenderer(Renderer9::makeRenderer9(renderer)),
26 mD3DUsage(usage),
27 mD3DPool(mRenderer->getTexturePool(usage))
28{
29}
30
31TextureStorage9::~TextureStorage9()
32{
33}
34
daniel@transgaming.com87705f82012-12-20 21:10:45 +000035TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage)
daniel@transgaming.com34da3972012-12-20 21:10:29 +000036{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +000037 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage));
daniel@transgaming.com34da3972012-12-20 21:10:29 +000038 return static_cast<TextureStorage9*>(storage);
39}
40
Jamie Madilld4589c92013-10-24 17:49:34 -040041DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, Renderer9 *renderer, bool renderTarget)
daniel@transgaming.com34da3972012-12-20 21:10:29 +000042{
shannonwoods@chromium.orgadc56352013-05-30 00:09:08 +000043 GLuint clientVersion = renderer->getCurrentClientVersion();
44
daniel@transgaming.com34da3972012-12-20 21:10:29 +000045 DWORD d3dusage = 0;
46
shannonwoods@chromium.orgadc56352013-05-30 00:09:08 +000047 if (gl::GetDepthBits(internalformat, clientVersion) > 0 ||
48 gl::GetStencilBits(internalformat, clientVersion) > 0)
daniel@transgaming.com34da3972012-12-20 21:10:29 +000049 {
50 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
51 }
Jamie Madilld4589c92013-10-24 17:49:34 -040052 else if (renderTarget && (gl_d3d9::GetRenderFormat(internalformat, renderer) != D3DFMT_UNKNOWN))
daniel@transgaming.com34da3972012-12-20 21:10:29 +000053 {
54 d3dusage |= D3DUSAGE_RENDERTARGET;
55 }
shannonwoods@chromium.orgadc56352013-05-30 00:09:08 +000056
daniel@transgaming.com34da3972012-12-20 21:10:29 +000057 return d3dusage;
58}
59
daniel@transgaming.com34da3972012-12-20 21:10:29 +000060
61bool TextureStorage9::isRenderTarget() const
62{
63 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
64}
65
66bool TextureStorage9::isManaged() const
67{
68 return (mD3DPool == D3DPOOL_MANAGED);
69}
70
71D3DPOOL TextureStorage9::getPool() const
72{
73 return mD3DPool;
74}
75
76DWORD TextureStorage9::getUsage() const
77{
78 return mD3DUsage;
79}
80
Nicolas Capensf61738a2014-03-31 14:50:18 -040081int TextureStorage9::getTopLevel() const
daniel@transgaming.com34da3972012-12-20 21:10:29 +000082{
Nicolas Capensf61738a2014-03-31 14:50:18 -040083 return mTopLevel;
daniel@transgaming.com34da3972012-12-20 21:10:29 +000084}
85
Nicolas Capensbf712d02014-03-31 14:23:35 -040086int TextureStorage9::getLevelCount() const
Jamie Madill4cfff5f2013-10-24 17:49:46 -040087{
Nicolas Capensfa7b76d2014-03-31 14:51:45 -040088 return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0;
Jamie Madill4cfff5f2013-10-24 17:49:46 -040089}
90
91TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain)
Nicolas Capensfa7b76d2014-03-31 14:51:45 -040092 : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
daniel@transgaming.com34da3972012-12-20 21:10:29 +000093{
94 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
95 mTexture = surfaceTexture;
daniel@transgaming.com5cdd0582013-01-11 04:07:35 +000096 mRenderTarget = NULL;
daniel@transgaming.com34da3972012-12-20 21:10:29 +000097
98 initializeRenderTarget();
99}
100
Nicolas Capensbf712d02014-03-31 14:23:35 -0400101TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels)
Nicolas Capensfa7b76d2014-03-31 14:51:45 -0400102 : TextureStorage9(renderer, GetTextureUsage(internalformat, Renderer9::makeRenderer9(renderer), renderTarget))
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000103{
104 mTexture = NULL;
daniel@transgaming.com5cdd0582013-01-11 04:07:35 +0000105 mRenderTarget = NULL;
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000106 // if the width or height is not positive this should be treated as an incomplete texture
107 // we handle that here by skipping the d3d texture creation
108 if (width > 0 && height > 0)
109 {
110 IDirect3DDevice9 *device = mRenderer->getDevice();
Shannon Woodsddb785c2013-07-08 10:32:13 -0400111 D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat, mRenderer);
Nicolas Capensf61738a2014-03-31 14:50:18 -0400112 d3d9::MakeValidSize(false, format, &width, &height, &mTopLevel);
Nicolas Capensbf712d02014-03-31 14:23:35 -0400113 UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels;
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400114
115 HRESULT result = device->CreateTexture(width, height, creationLevels, getUsage(), format, getPool(), &mTexture, NULL);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000116
117 if (FAILED(result))
118 {
119 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000120 gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000121 }
122 }
123
124 initializeRenderTarget();
125}
126
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000127TextureStorage9_2D::~TextureStorage9_2D()
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000128{
Geoff Langea228632013-07-30 15:17:12 -0400129 SafeRelease(mTexture);
130 SafeDelete(mRenderTarget);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000131}
132
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000133TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000134{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +0000135 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage));
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000136 return static_cast<TextureStorage9_2D*>(storage);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000137}
138
139// Increments refcount on surface.
140// caller must Release() the returned surface
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000141IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000142{
143 IDirect3DSurface9 *surface = NULL;
144
145 if (mTexture)
146 {
Nicolas Capensf61738a2014-03-31 14:50:18 -0400147 HRESULT result = mTexture->GetSurfaceLevel(level + mTopLevel, &surface);
Geoff Lang9cd19152014-05-28 15:54:34 -0400148 UNUSED_ASSERTION_VARIABLE(result);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000149 ASSERT(SUCCEEDED(result));
150
151 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
Nicolas Capensf61738a2014-03-31 14:50:18 -0400152 if (level + mTopLevel != 0 && isManaged() && dirty)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000153 {
154 mTexture->AddDirtyRect(NULL);
155 }
156 }
157
158 return surface;
159}
160
shannon.woods%transgaming.com@gtempaccount.com63b3b8f2013-04-13 03:43:26 +0000161RenderTarget *TextureStorage9_2D::getRenderTarget(int level)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000162{
163 return mRenderTarget;
164}
165
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000166void TextureStorage9_2D::generateMipmap(int level)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000167{
168 IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
169 IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
170
171 if (upper != NULL && lower != NULL)
172 {
173 mRenderer->boxFilter(upper, lower);
174 }
175
Geoff Langea228632013-07-30 15:17:12 -0400176 SafeRelease(upper);
177 SafeRelease(lower);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000178}
179
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000180IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000181{
182 return mTexture;
183}
184
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000185void TextureStorage9_2D::initializeRenderTarget()
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000186{
daniel@transgaming.com5cdd0582013-01-11 04:07:35 +0000187 ASSERT(mRenderTarget == NULL);
188
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000189 if (mTexture != NULL && isRenderTarget())
190 {
191 IDirect3DSurface9 *surface = getSurfaceLevel(0, false);
192
193 mRenderTarget = new RenderTarget9(mRenderer, surface);
194 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000195}
196
Nicolas Capensbf712d02014-03-31 14:23:35 -0400197TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels)
Nicolas Capensfa7b76d2014-03-31 14:51:45 -0400198 : TextureStorage9(renderer, GetTextureUsage(internalformat, Renderer9::makeRenderer9(renderer), renderTarget))
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000199{
200 mTexture = NULL;
daniel@transgaming.com5cdd0582013-01-11 04:07:35 +0000201 for (int i = 0; i < 6; ++i)
202 {
203 mRenderTarget[i] = NULL;
204 }
205
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000206 // if the size is not positive this should be treated as an incomplete texture
207 // we handle that here by skipping the d3d texture creation
208 if (size > 0)
209 {
210 IDirect3DDevice9 *device = mRenderer->getDevice();
211 int height = size;
Shannon Woodsddb785c2013-07-08 10:32:13 -0400212 D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat, mRenderer);
Nicolas Capensf61738a2014-03-31 14:50:18 -0400213 d3d9::MakeValidSize(false, format, &size, &height, &mTopLevel);
Nicolas Capensbf712d02014-03-31 14:23:35 -0400214 UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels;
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400215
216 HRESULT result = device->CreateCubeTexture(size, creationLevels, getUsage(), format, getPool(), &mTexture, NULL);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000217
218 if (FAILED(result))
219 {
220 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000221 gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000222 }
223 }
224
225 initializeRenderTarget();
226}
227
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000228TextureStorage9_Cube::~TextureStorage9_Cube()
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000229{
Geoff Langea228632013-07-30 15:17:12 -0400230 SafeRelease(mTexture);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000231
232 for (int i = 0; i < 6; ++i)
233 {
Geoff Langea228632013-07-30 15:17:12 -0400234 SafeDelete(mRenderTarget[i]);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000235 }
236}
237
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000238TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000239{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +0000240 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage));
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000241 return static_cast<TextureStorage9_Cube*>(storage);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000242}
243
244// Increments refcount on surface.
245// caller must Release() the returned surface
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000246IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000247{
248 IDirect3DSurface9 *surface = NULL;
249
250 if (mTexture)
251 {
252 D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
Nicolas Capensf61738a2014-03-31 14:50:18 -0400253 HRESULT result = mTexture->GetCubeMapSurface(face, level + mTopLevel, &surface);
Geoff Lang9cd19152014-05-28 15:54:34 -0400254 UNUSED_ASSERTION_VARIABLE(result);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000255 ASSERT(SUCCEEDED(result));
256
257 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
258 if (level != 0 && isManaged() && dirty)
259 {
260 mTexture->AddDirtyRect(face, NULL);
261 }
262 }
263
264 return surface;
265}
266
Nicolas Capens930f05e2013-06-18 15:31:58 -0400267RenderTarget *TextureStorage9_Cube::getRenderTargetFace(GLenum faceTarget, int level)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000268{
Jamie Madill2db197c2013-10-24 17:49:35 -0400269 return mRenderTarget[gl::TextureCubeMap::targetToIndex(faceTarget)];
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000270}
271
Jamie Madill2db197c2013-10-24 17:49:35 -0400272void TextureStorage9_Cube::generateMipmap(int faceIndex, int level)
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000273{
Jamie Madill2db197c2013-10-24 17:49:35 -0400274 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1, false);
275 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, true);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000276
277 if (upper != NULL && lower != NULL)
278 {
279 mRenderer->boxFilter(upper, lower);
280 }
281
Geoff Langea228632013-07-30 15:17:12 -0400282 SafeRelease(upper);
283 SafeRelease(lower);
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000284}
285
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000286IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000287{
288 return mTexture;
289}
290
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000291void TextureStorage9_Cube::initializeRenderTarget()
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000292{
293 if (mTexture != NULL && isRenderTarget())
294 {
295 IDirect3DSurface9 *surface = NULL;
296
297 for (int i = 0; i < 6; ++i)
298 {
daniel@transgaming.com5cdd0582013-01-11 04:07:35 +0000299 ASSERT(mRenderTarget[i] == NULL);
300
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000301 surface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, false);
302
303 mRenderTarget[i] = new RenderTarget9(mRenderer, surface);
304 }
305 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000306}
307
308}