blob: a2afc3c318c730632380560b786603b11a66e7b4 [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.comb5e1a272012-10-31 19:10:00 +000014
15#include "common/debug.h"
16
17namespace gl
18{
19unsigned int TextureStorage::mCurrentTextureSerial = 1;
20
21TextureStorage::TextureStorage(DWORD usage)
22 : mD3DUsage(usage),
23 mD3DPool(getDisplay()->getRenderer()->getTexturePool(usage)), // D3D9_REPLACE
24 mTextureSerial(issueTextureSerial()),
25 mLodOffset(0)
26{
27}
28
29TextureStorage::~TextureStorage()
30{
31}
32
daniel@transgaming.comdf14c762012-10-31 19:51:48 +000033DWORD TextureStorage::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
34{
35 DWORD d3dusage = 0;
36
37 if (d3dfmt == D3DFMT_INTZ)
38 {
39 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
40 }
41 else if(forceRenderable || (TextureStorage::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
42 {
43 d3dusage |= D3DUSAGE_RENDERTARGET;
44 }
45 return d3dusage;
46}
47
48bool TextureStorage::IsTextureFormatRenderable(D3DFORMAT format)
49{
50 if (format == D3DFMT_INTZ)
51 {
52 return true;
53 }
54 switch(format)
55 {
56 case D3DFMT_L8:
57 case D3DFMT_A8L8:
58 case D3DFMT_DXT1:
59 case D3DFMT_DXT3:
60 case D3DFMT_DXT5:
61 return false;
62 case D3DFMT_A8R8G8B8:
63 case D3DFMT_X8R8G8B8:
64 case D3DFMT_A16B16G16R16F:
65 case D3DFMT_A32B32G32R32F:
66 return true;
67 default:
68 UNREACHABLE();
69 }
70
71 return false;
72}
73
74D3DFORMAT TextureStorage::ConvertTextureInternalFormat(GLint internalformat)
75{
76 switch (internalformat)
77 {
78 case GL_DEPTH_COMPONENT16:
79 case GL_DEPTH_COMPONENT32_OES:
80 case GL_DEPTH24_STENCIL8_OES:
81 return D3DFMT_INTZ;
82 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
83 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
84 return D3DFMT_DXT1;
85 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
86 return D3DFMT_DXT3;
87 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
88 return D3DFMT_DXT5;
89 case GL_RGBA32F_EXT:
90 case GL_RGB32F_EXT:
91 case GL_ALPHA32F_EXT:
92 case GL_LUMINANCE32F_EXT:
93 case GL_LUMINANCE_ALPHA32F_EXT:
94 return D3DFMT_A32B32G32R32F;
95 case GL_RGBA16F_EXT:
96 case GL_RGB16F_EXT:
97 case GL_ALPHA16F_EXT:
98 case GL_LUMINANCE16F_EXT:
99 case GL_LUMINANCE_ALPHA16F_EXT:
100 return D3DFMT_A16B16G16R16F;
101 case GL_LUMINANCE8_EXT:
102 if (getContext()->supportsLuminanceTextures())
103 {
104 return D3DFMT_L8;
105 }
106 break;
107 case GL_LUMINANCE8_ALPHA8_EXT:
108 if (getContext()->supportsLuminanceAlphaTextures())
109 {
110 return D3DFMT_A8L8;
111 }
112 break;
113 case GL_RGB8_OES:
114 case GL_RGB565:
115 return D3DFMT_X8R8G8B8;
116 }
117
118 return D3DFMT_A8R8G8B8;
119}
120
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000121bool TextureStorage::isRenderTarget() const
122{
123 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
124}
125
126bool TextureStorage::isManaged() const
127{
128 return (mD3DPool == D3DPOOL_MANAGED);
129}
130
131D3DPOOL TextureStorage::getPool() const
132{
133 return mD3DPool;
134}
135
136DWORD TextureStorage::getUsage() const
137{
138 return mD3DUsage;
139}
140
141unsigned int TextureStorage::getTextureSerial() const
142{
143 return mTextureSerial;
144}
145
146unsigned int TextureStorage::issueTextureSerial()
147{
148 return mCurrentTextureSerial++;
149}
150
151int TextureStorage::getLodOffset() const
152{
153 return mLodOffset;
154}
155
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000156int TextureStorage::levelCount()
157{
158 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
159}
160
161bool TextureStorage::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
162{
163 if (source && dest)
164 {
165 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
166 renderer::Renderer9 *renderer = getDisplay()->getRenderer();
167 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
168
169 if (fromManaged)
170 {
171 D3DSURFACE_DESC desc;
172 source->GetDesc(&desc);
173
174 IDirect3DSurface9 *surf = 0;
175 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
176
177 if (SUCCEEDED(result))
178 {
179 Image::CopyLockableSurfaces(surf, source);
180 result = device->UpdateSurface(surf, NULL, dest, NULL);
181 surf->Release();
182 }
183 }
184 else
185 {
186 renderer->endScene();
187 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
188 }
189
190 if (FAILED(result))
191 {
192 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
193 return false;
194 }
195 }
196
197 return true;
198}
199
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000200TextureStorage2D::TextureStorage2D(renderer::SwapChain *swapchain) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000201{
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000202 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000203 mTexture = surfaceTexture;
204}
205
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000206TextureStorage2D::TextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
207 : TextureStorage(GetTextureUsage(ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
208 mRenderTargetSerial(RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000209{
210 mTexture = NULL;
211 // if the width or height is not positive this should be treated as an incomplete texture
212 // we handle that here by skipping the d3d texture creation
213 if (width > 0 && height > 0)
214 {
215 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice(); // D3D9_REPLACE
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000216 MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
217 HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
218 ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000219
220 if (FAILED(result))
221 {
222 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
223 error(GL_OUT_OF_MEMORY);
224 }
225 }
226}
227
228TextureStorage2D::~TextureStorage2D()
229{
230 if (mTexture)
231 {
232 mTexture->Release();
233 }
234}
235
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000236bool TextureStorage2D::copyToRenderTarget(TextureStorage2D *dest, TextureStorage2D *source)
237{
238 bool result = false;
239
240 if (source && dest)
241 {
242 int levels = source->levelCount();
243 for (int i = 0; i < levels; ++i)
244 {
245 IDirect3DSurface9 *srcSurf = source->getSurfaceLevel(i, false);
246 IDirect3DSurface9 *dstSurf = dest->getSurfaceLevel(i, false);
247
248 result = TextureStorage::copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
249
250 if (srcSurf) srcSurf->Release();
251 if (dstSurf) dstSurf->Release();
252
253 if (!result)
254 return false;
255 }
256 }
257
258 return result;
259}
260
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000261// Increments refcount on surface.
262// caller must Release() the returned surface
263IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty)
264{
265 IDirect3DSurface9 *surface = NULL;
266
267 if (mTexture)
268 {
269 HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
270 ASSERT(SUCCEEDED(result));
271
272 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
273 if (level != 0 && isManaged() && dirty)
274 {
275 mTexture->AddDirtyRect(NULL);
276 }
277 }
278
279 return surface;
280}
281
282IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
283{
284 return mTexture;
285}
286
287unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
288{
289 return mRenderTargetSerial;
290}
291
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000292TextureStorageCubeMap::TextureStorageCubeMap(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
293 : TextureStorage(GetTextureUsage(ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
294 mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000295{
296 mTexture = NULL;
297 // if the size is not positive this should be treated as an incomplete texture
298 // we handle that here by skipping the d3d texture creation
299 if (size > 0)
300 {
301 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice(); // D3D9_REPLACE
302 int height = size;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000303 MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
304 HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
305 ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000306
307 if (FAILED(result))
308 {
309 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
310 error(GL_OUT_OF_MEMORY);
311 }
312 }
313}
314
315TextureStorageCubeMap::~TextureStorageCubeMap()
316{
317 if (mTexture)
318 {
319 mTexture->Release();
320 }
321}
322
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000323bool TextureStorageCubeMap::copyToRenderTarget(TextureStorageCubeMap *dest, TextureStorageCubeMap *source)
324{
325 bool result = false;
326
327 if (source && dest)
328 {
329 int levels = source->levelCount();
330 for (int f = 0; f < 6; f++)
331 {
332 for (int i = 0; i < levels; i++)
333 {
334 IDirect3DSurface9 *srcSurf = source->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
335 IDirect3DSurface9 *dstSurf = dest->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
336
337 result = TextureStorage::copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
338
339 if (srcSurf) srcSurf->Release();
340 if (dstSurf) dstSurf->Release();
341
342 if (!result)
343 return false;
344 }
345 }
346 }
347
348 return result;
349}
350
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000351// Increments refcount on surface.
352// caller must Release() the returned surface
353IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
354{
355 IDirect3DSurface9 *surface = NULL;
356
357 if (mTexture)
358 {
359 D3DCUBEMAP_FACES face = es2dx::ConvertCubeFace(faceTarget);
360 HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
361 ASSERT(SUCCEEDED(result));
362
363 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
364 if (level != 0 && isManaged() && dirty)
365 {
366 mTexture->AddDirtyRect(face, NULL);
367 }
368 }
369
370 return surface;
371}
372
373IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
374{
375 return mTexture;
376}
377
378unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
379{
380 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
381}
382
383}