blob: 4cb561e2620dcabcc691b1f70ee53ae3e977abe7 [file] [log] [blame]
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +00001//
2// Copyright (c) 2002-2012 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.
5//
6
7// TextureStorage.cpp: Implements the abstract gl::TextureStorage class and its concrete derived
8// classes TextureStorage2D and TextureStorageCubeMap, which act as the interface to the
9// D3D-side texture.
10
11#include "libGLESv2/main.h"
12#include "libGLESv2/renderer/TextureStorage.h"
daniel@transgaming.com25ee7442012-10-31 19:51:56 +000013#include "libGLESv2/renderer/SwapChain.h"
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +000014#include "libGLESv2/Blit.h"
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000015
16#include "common/debug.h"
17
18namespace gl
19{
20unsigned int TextureStorage::mCurrentTextureSerial = 1;
21
22TextureStorage::TextureStorage(DWORD usage)
23 : mD3DUsage(usage),
24 mD3DPool(getDisplay()->getRenderer()->getTexturePool(usage)), // D3D9_REPLACE
25 mTextureSerial(issueTextureSerial()),
26 mLodOffset(0)
27{
28}
29
30TextureStorage::~TextureStorage()
31{
32}
33
daniel@transgaming.comdf14c762012-10-31 19:51:48 +000034DWORD TextureStorage::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
35{
36 DWORD d3dusage = 0;
37
38 if (d3dfmt == D3DFMT_INTZ)
39 {
40 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
41 }
42 else if(forceRenderable || (TextureStorage::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
43 {
44 d3dusage |= D3DUSAGE_RENDERTARGET;
45 }
46 return d3dusage;
47}
48
49bool TextureStorage::IsTextureFormatRenderable(D3DFORMAT format)
50{
51 if (format == D3DFMT_INTZ)
52 {
53 return true;
54 }
55 switch(format)
56 {
57 case D3DFMT_L8:
58 case D3DFMT_A8L8:
59 case D3DFMT_DXT1:
60 case D3DFMT_DXT3:
61 case D3DFMT_DXT5:
62 return false;
63 case D3DFMT_A8R8G8B8:
64 case D3DFMT_X8R8G8B8:
65 case D3DFMT_A16B16G16R16F:
66 case D3DFMT_A32B32G32R32F:
67 return true;
68 default:
69 UNREACHABLE();
70 }
71
72 return false;
73}
74
75D3DFORMAT TextureStorage::ConvertTextureInternalFormat(GLint internalformat)
76{
77 switch (internalformat)
78 {
79 case GL_DEPTH_COMPONENT16:
80 case GL_DEPTH_COMPONENT32_OES:
81 case GL_DEPTH24_STENCIL8_OES:
82 return D3DFMT_INTZ;
83 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
84 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
85 return D3DFMT_DXT1;
86 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
87 return D3DFMT_DXT3;
88 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
89 return D3DFMT_DXT5;
90 case GL_RGBA32F_EXT:
91 case GL_RGB32F_EXT:
92 case GL_ALPHA32F_EXT:
93 case GL_LUMINANCE32F_EXT:
94 case GL_LUMINANCE_ALPHA32F_EXT:
95 return D3DFMT_A32B32G32R32F;
96 case GL_RGBA16F_EXT:
97 case GL_RGB16F_EXT:
98 case GL_ALPHA16F_EXT:
99 case GL_LUMINANCE16F_EXT:
100 case GL_LUMINANCE_ALPHA16F_EXT:
101 return D3DFMT_A16B16G16R16F;
102 case GL_LUMINANCE8_EXT:
103 if (getContext()->supportsLuminanceTextures())
104 {
105 return D3DFMT_L8;
106 }
107 break;
108 case GL_LUMINANCE8_ALPHA8_EXT:
109 if (getContext()->supportsLuminanceAlphaTextures())
110 {
111 return D3DFMT_A8L8;
112 }
113 break;
114 case GL_RGB8_OES:
115 case GL_RGB565:
116 return D3DFMT_X8R8G8B8;
117 }
118
119 return D3DFMT_A8R8G8B8;
120}
121
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000122Blit *TextureStorage::getBlitter()
123{
124 Context *context = getContext();
125 return context->getBlitter();
126}
127
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000128bool TextureStorage::isRenderTarget() const
129{
130 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
131}
132
133bool TextureStorage::isManaged() const
134{
135 return (mD3DPool == D3DPOOL_MANAGED);
136}
137
138D3DPOOL TextureStorage::getPool() const
139{
140 return mD3DPool;
141}
142
143DWORD TextureStorage::getUsage() const
144{
145 return mD3DUsage;
146}
147
148unsigned int TextureStorage::getTextureSerial() const
149{
150 return mTextureSerial;
151}
152
153unsigned int TextureStorage::issueTextureSerial()
154{
155 return mCurrentTextureSerial++;
156}
157
158int TextureStorage::getLodOffset() const
159{
160 return mLodOffset;
161}
162
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000163int TextureStorage::levelCount()
164{
165 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
166}
167
168bool TextureStorage::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
169{
170 if (source && dest)
171 {
172 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
173 renderer::Renderer9 *renderer = getDisplay()->getRenderer();
174 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
175
176 if (fromManaged)
177 {
178 D3DSURFACE_DESC desc;
179 source->GetDesc(&desc);
180
181 IDirect3DSurface9 *surf = 0;
182 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
183
184 if (SUCCEEDED(result))
185 {
186 Image::CopyLockableSurfaces(surf, source);
187 result = device->UpdateSurface(surf, NULL, dest, NULL);
188 surf->Release();
189 }
190 }
191 else
192 {
193 renderer->endScene();
194 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
195 }
196
197 if (FAILED(result))
198 {
199 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
200 return false;
201 }
202 }
203
204 return true;
205}
206
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000207TextureStorage2D::TextureStorage2D(renderer::SwapChain *swapchain) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000208{
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000209 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000210 mTexture = surfaceTexture;
211}
212
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000213TextureStorage2D::TextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
214 : TextureStorage(GetTextureUsage(ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
215 mRenderTargetSerial(RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000216{
217 mTexture = NULL;
218 // if the width or height is not positive this should be treated as an incomplete texture
219 // we handle that here by skipping the d3d texture creation
220 if (width > 0 && height > 0)
221 {
222 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice(); // D3D9_REPLACE
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000223 MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
224 HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
225 ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000226
227 if (FAILED(result))
228 {
229 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
230 error(GL_OUT_OF_MEMORY);
231 }
232 }
233}
234
235TextureStorage2D::~TextureStorage2D()
236{
237 if (mTexture)
238 {
239 mTexture->Release();
240 }
241}
242
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000243bool TextureStorage2D::copyToRenderTarget(TextureStorage2D *dest, TextureStorage2D *source)
244{
245 bool result = false;
246
247 if (source && dest)
248 {
249 int levels = source->levelCount();
250 for (int i = 0; i < levels; ++i)
251 {
252 IDirect3DSurface9 *srcSurf = source->getSurfaceLevel(i, false);
253 IDirect3DSurface9 *dstSurf = dest->getSurfaceLevel(i, false);
254
255 result = TextureStorage::copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
256
257 if (srcSurf) srcSurf->Release();
258 if (dstSurf) dstSurf->Release();
259
260 if (!result)
261 return false;
262 }
263 }
264
265 return result;
266}
267
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000268// Increments refcount on surface.
269// caller must Release() the returned surface
270IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty)
271{
272 IDirect3DSurface9 *surface = NULL;
273
274 if (mTexture)
275 {
276 HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
277 ASSERT(SUCCEEDED(result));
278
279 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
280 if (level != 0 && isManaged() && dirty)
281 {
282 mTexture->AddDirtyRect(NULL);
283 }
284 }
285
286 return surface;
287}
288
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000289void TextureStorage2D::generateMipmap(int level)
290{
291 IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
292 IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
293
294 if (upper != NULL && lower != NULL)
295 {
296 getBlitter()->boxFilter(upper, lower);
297 }
298
299 if (upper != NULL) upper->Release();
300 if (lower != NULL) lower->Release();
301}
302
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000303IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
304{
305 return mTexture;
306}
307
308unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
309{
310 return mRenderTargetSerial;
311}
312
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000313TextureStorageCubeMap::TextureStorageCubeMap(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
314 : TextureStorage(GetTextureUsage(ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
315 mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000316{
317 mTexture = NULL;
318 // if the size is not positive this should be treated as an incomplete texture
319 // we handle that here by skipping the d3d texture creation
320 if (size > 0)
321 {
322 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice(); // D3D9_REPLACE
323 int height = size;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000324 MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
325 HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
326 ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000327
328 if (FAILED(result))
329 {
330 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
331 error(GL_OUT_OF_MEMORY);
332 }
333 }
334}
335
336TextureStorageCubeMap::~TextureStorageCubeMap()
337{
338 if (mTexture)
339 {
340 mTexture->Release();
341 }
342}
343
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000344bool TextureStorageCubeMap::copyToRenderTarget(TextureStorageCubeMap *dest, TextureStorageCubeMap *source)
345{
346 bool result = false;
347
348 if (source && dest)
349 {
350 int levels = source->levelCount();
351 for (int f = 0; f < 6; f++)
352 {
353 for (int i = 0; i < levels; i++)
354 {
355 IDirect3DSurface9 *srcSurf = source->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
356 IDirect3DSurface9 *dstSurf = dest->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
357
358 result = TextureStorage::copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
359
360 if (srcSurf) srcSurf->Release();
361 if (dstSurf) dstSurf->Release();
362
363 if (!result)
364 return false;
365 }
366 }
367 }
368
369 return result;
370}
371
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000372// Increments refcount on surface.
373// caller must Release() the returned surface
374IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
375{
376 IDirect3DSurface9 *surface = NULL;
377
378 if (mTexture)
379 {
380 D3DCUBEMAP_FACES face = es2dx::ConvertCubeFace(faceTarget);
381 HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
382 ASSERT(SUCCEEDED(result));
383
384 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
385 if (level != 0 && isManaged() && dirty)
386 {
387 mTexture->AddDirtyRect(face, NULL);
388 }
389 }
390
391 return surface;
392}
393
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000394void TextureStorageCubeMap::generateMipmap(int face, int level)
395{
396 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false);
397 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
398
399 if (upper != NULL && lower != NULL)
400 {
401 getBlitter()->boxFilter(upper, lower);
402 }
403
404 if (upper != NULL) upper->Release();
405 if (lower != NULL) lower->Release();
406}
407
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000408IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
409{
410 return mTexture;
411}
412
413unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
414{
415 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
416}
417
418}