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