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