1 #include "precompiled.h"
2 //
3 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
4 // 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
9 // classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
10 // D3D9 texture.
11
12 #include "libGLESv2/main.h"
13 #include "libGLESv2/renderer/Renderer9.h"
14 #include "libGLESv2/renderer/TextureStorage9.h"
15 #include "libGLESv2/renderer/SwapChain9.h"
16 #include "libGLESv2/renderer/RenderTarget9.h"
17 #include "libGLESv2/renderer/renderer9_utils.h"
18 #include "libGLESv2/Texture.h"
19
20 namespace rx
21 {
TextureStorage9(Renderer * renderer,DWORD usage)22 TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage)
23 : mLodOffset(0),
24 mRenderer(Renderer9::makeRenderer9(renderer)),
25 mD3DUsage(usage),
26 mD3DPool(mRenderer->getTexturePool(usage))
27 {
28 }
29
~TextureStorage9()30 TextureStorage9::~TextureStorage9()
31 {
32 }
33
makeTextureStorage9(TextureStorage * storage)34 TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage)
35 {
36 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage));
37 return static_cast<TextureStorage9*>(storage);
38 }
39
GetTextureUsage(D3DFORMAT d3dfmt,GLenum glusage,bool forceRenderable)40 DWORD TextureStorage9::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
41 {
42 DWORD d3dusage = 0;
43
44 if (d3dfmt == D3DFMT_INTZ)
45 {
46 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
47 }
48 else if(forceRenderable || (TextureStorage9::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
49 {
50 d3dusage |= D3DUSAGE_RENDERTARGET;
51 }
52 return d3dusage;
53 }
54
IsTextureFormatRenderable(D3DFORMAT format)55 bool TextureStorage9::IsTextureFormatRenderable(D3DFORMAT format)
56 {
57 if (format == D3DFMT_INTZ)
58 {
59 return true;
60 }
61 switch(format)
62 {
63 case D3DFMT_L8:
64 case D3DFMT_A8L8:
65 case D3DFMT_DXT1:
66 case D3DFMT_DXT3:
67 case D3DFMT_DXT5:
68 return false;
69 case D3DFMT_A8R8G8B8:
70 case D3DFMT_X8R8G8B8:
71 case D3DFMT_A16B16G16R16F:
72 case D3DFMT_A32B32G32R32F:
73 return true;
74 default:
75 UNREACHABLE();
76 }
77
78 return false;
79 }
80
isRenderTarget() const81 bool TextureStorage9::isRenderTarget() const
82 {
83 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
84 }
85
isManaged() const86 bool TextureStorage9::isManaged() const
87 {
88 return (mD3DPool == D3DPOOL_MANAGED);
89 }
90
getPool() const91 D3DPOOL TextureStorage9::getPool() const
92 {
93 return mD3DPool;
94 }
95
getUsage() const96 DWORD TextureStorage9::getUsage() const
97 {
98 return mD3DUsage;
99 }
100
getLodOffset() const101 int TextureStorage9::getLodOffset() const
102 {
103 return mLodOffset;
104 }
105
levelCount()106 int TextureStorage9::levelCount()
107 {
108 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
109 }
110
TextureStorage9_2D(Renderer * renderer,SwapChain9 * swapchain)111 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
112 {
113 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
114 mTexture = surfaceTexture;
115 mRenderTarget = NULL;
116
117 initializeRenderTarget();
118 }
119
TextureStorage9_2D(Renderer * renderer,int levels,GLenum internalformat,GLenum usage,bool forceRenderable,GLsizei width,GLsizei height)120 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
121 : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable))
122 {
123 mTexture = NULL;
124 mRenderTarget = NULL;
125 // if the width or height is not positive this should be treated as an incomplete texture
126 // we handle that here by skipping the d3d texture creation
127 if (width > 0 && height > 0)
128 {
129 IDirect3DDevice9 *device = mRenderer->getDevice();
130 gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
131 HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
132 mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
133
134 if (FAILED(result))
135 {
136 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
137 gl::error(GL_OUT_OF_MEMORY);
138 }
139 }
140
141 initializeRenderTarget();
142 }
143
~TextureStorage9_2D()144 TextureStorage9_2D::~TextureStorage9_2D()
145 {
146 if (mTexture)
147 {
148 mTexture->Release();
149 }
150
151 delete mRenderTarget;
152 }
153
makeTextureStorage9_2D(TextureStorage * storage)154 TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage)
155 {
156 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage));
157 return static_cast<TextureStorage9_2D*>(storage);
158 }
159
160 // Increments refcount on surface.
161 // caller must Release() the returned surface
getSurfaceLevel(int level,bool dirty)162 IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty)
163 {
164 IDirect3DSurface9 *surface = NULL;
165
166 if (mTexture)
167 {
168 HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
169 ASSERT(SUCCEEDED(result));
170
171 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
172 if (level + mLodOffset != 0 && isManaged() && dirty)
173 {
174 mTexture->AddDirtyRect(NULL);
175 }
176 }
177
178 return surface;
179 }
180
getRenderTarget()181 RenderTarget *TextureStorage9_2D::getRenderTarget()
182 {
183 return mRenderTarget;
184 }
185
generateMipmap(int level)186 void TextureStorage9_2D::generateMipmap(int level)
187 {
188 IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
189 IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
190
191 if (upper != NULL && lower != NULL)
192 {
193 mRenderer->boxFilter(upper, lower);
194 }
195
196 if (upper != NULL) upper->Release();
197 if (lower != NULL) lower->Release();
198 }
199
getBaseTexture() const200 IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const
201 {
202 return mTexture;
203 }
204
initializeRenderTarget()205 void TextureStorage9_2D::initializeRenderTarget()
206 {
207 ASSERT(mRenderTarget == NULL);
208
209 if (mTexture != NULL && isRenderTarget())
210 {
211 IDirect3DSurface9 *surface = getSurfaceLevel(0, false);
212
213 mRenderTarget = new RenderTarget9(mRenderer, surface);
214 }
215 }
216
TextureStorage9_Cube(Renderer * renderer,int levels,GLenum internalformat,GLenum usage,bool forceRenderable,int size)217 TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
218 : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable))
219 {
220 mTexture = NULL;
221 for (int i = 0; i < 6; ++i)
222 {
223 mRenderTarget[i] = NULL;
224 }
225
226 // if the size is not positive this should be treated as an incomplete texture
227 // we handle that here by skipping the d3d texture creation
228 if (size > 0)
229 {
230 IDirect3DDevice9 *device = mRenderer->getDevice();
231 int height = size;
232 gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
233 HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
234 mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
235
236 if (FAILED(result))
237 {
238 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
239 gl::error(GL_OUT_OF_MEMORY);
240 }
241 }
242
243 initializeRenderTarget();
244 }
245
~TextureStorage9_Cube()246 TextureStorage9_Cube::~TextureStorage9_Cube()
247 {
248 if (mTexture)
249 {
250 mTexture->Release();
251 }
252
253 for (int i = 0; i < 6; ++i)
254 {
255 delete mRenderTarget[i];
256 }
257 }
258
makeTextureStorage9_Cube(TextureStorage * storage)259 TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage)
260 {
261 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage));
262 return static_cast<TextureStorage9_Cube*>(storage);
263 }
264
265 // Increments refcount on surface.
266 // caller must Release() the returned surface
getCubeMapSurface(GLenum faceTarget,int level,bool dirty)267 IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
268 {
269 IDirect3DSurface9 *surface = NULL;
270
271 if (mTexture)
272 {
273 D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
274 HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
275 ASSERT(SUCCEEDED(result));
276
277 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
278 if (level != 0 && isManaged() && dirty)
279 {
280 mTexture->AddDirtyRect(face, NULL);
281 }
282 }
283
284 return surface;
285 }
286
getRenderTarget(GLenum faceTarget)287 RenderTarget *TextureStorage9_Cube::getRenderTarget(GLenum faceTarget)
288 {
289 return mRenderTarget[gl::TextureCubeMap::faceIndex(faceTarget)];
290 }
291
generateMipmap(int face,int level)292 void TextureStorage9_Cube::generateMipmap(int face, int level)
293 {
294 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false);
295 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
296
297 if (upper != NULL && lower != NULL)
298 {
299 mRenderer->boxFilter(upper, lower);
300 }
301
302 if (upper != NULL) upper->Release();
303 if (lower != NULL) lower->Release();
304 }
305
getBaseTexture() const306 IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const
307 {
308 return mTexture;
309 }
310
initializeRenderTarget()311 void TextureStorage9_Cube::initializeRenderTarget()
312 {
313 if (mTexture != NULL && isRenderTarget())
314 {
315 IDirect3DSurface9 *surface = NULL;
316
317 for (int i = 0; i < 6; ++i)
318 {
319 ASSERT(mRenderTarget[i] == NULL);
320
321 surface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, false);
322
323 mRenderTarget[i] = new RenderTarget9(mRenderer, surface);
324 }
325 }
326 }
327
328 }