blob: f42deab4c4dfa7c1ea281ec3e5bbd0a32fb04a14 [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.coma9571682012-11-28 19:33:08 +000024TextureStorage::TextureStorage(rx::Renderer9 *renderer, DWORD usage)
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000025 : mD3DUsage(usage),
daniel@transgaming.coma9571682012-11-28 19:33:08 +000026 mD3DPool(renderer->getTexturePool(usage)),
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
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +000078Blit *TextureStorage::getBlitter()
79{
80 Context *context = getContext();
81 return context->getBlitter();
82}
83
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000084bool TextureStorage::isRenderTarget() const
85{
86 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
87}
88
89bool TextureStorage::isManaged() const
90{
91 return (mD3DPool == D3DPOOL_MANAGED);
92}
93
94D3DPOOL TextureStorage::getPool() const
95{
96 return mD3DPool;
97}
98
99DWORD TextureStorage::getUsage() const
100{
101 return mD3DUsage;
102}
103
104unsigned int TextureStorage::getTextureSerial() const
105{
106 return mTextureSerial;
107}
108
109unsigned int TextureStorage::issueTextureSerial()
110{
111 return mCurrentTextureSerial++;
112}
113
114int TextureStorage::getLodOffset() const
115{
116 return mLodOffset;
117}
118
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000119int TextureStorage::levelCount()
120{
121 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
122}
123
124bool TextureStorage::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
125{
126 if (source && dest)
127 {
128 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
daniel@transgaming.com76d3e6e2012-10-31 19:55:33 +0000129 rx::Renderer9 *renderer = getDisplay()->getRenderer9();
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000130 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
131
132 if (fromManaged)
133 {
134 D3DSURFACE_DESC desc;
135 source->GetDesc(&desc);
136
137 IDirect3DSurface9 *surf = 0;
138 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
139
140 if (SUCCEEDED(result))
141 {
142 Image::CopyLockableSurfaces(surf, source);
143 result = device->UpdateSurface(surf, NULL, dest, NULL);
144 surf->Release();
145 }
146 }
147 else
148 {
149 renderer->endScene();
150 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
151 }
152
153 if (FAILED(result))
154 {
155 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
156 return false;
157 }
158 }
159
160 return true;
161}
162
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000163TextureStorage2D::TextureStorage2D(rx::Renderer9 *renderer, rx::SwapChain *swapchain) : TextureStorage(renderer, D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000164{
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000165 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000166 mTexture = surfaceTexture;
167}
168
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000169TextureStorage2D::TextureStorage2D(rx::Renderer9 *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
170 : TextureStorage(renderer, GetTextureUsage(renderer->ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000171 mRenderTargetSerial(RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000172{
173 mTexture = NULL;
174 // if the width or height is not positive this should be treated as an incomplete texture
175 // we handle that here by skipping the d3d texture creation
176 if (width > 0 && height > 0)
177 {
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000178 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000179 MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
180 HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000181 renderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000182
183 if (FAILED(result))
184 {
185 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
186 error(GL_OUT_OF_MEMORY);
187 }
188 }
189}
190
191TextureStorage2D::~TextureStorage2D()
192{
193 if (mTexture)
194 {
195 mTexture->Release();
196 }
197}
198
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000199bool TextureStorage2D::copyToRenderTarget(TextureStorage2D *dest, TextureStorage2D *source)
200{
201 bool result = false;
202
203 if (source && dest)
204 {
205 int levels = source->levelCount();
206 for (int i = 0; i < levels; ++i)
207 {
208 IDirect3DSurface9 *srcSurf = source->getSurfaceLevel(i, false);
209 IDirect3DSurface9 *dstSurf = dest->getSurfaceLevel(i, false);
210
211 result = TextureStorage::copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
212
213 if (srcSurf) srcSurf->Release();
214 if (dstSurf) dstSurf->Release();
215
216 if (!result)
217 return false;
218 }
219 }
220
221 return result;
222}
223
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000224// Increments refcount on surface.
225// caller must Release() the returned surface
226IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty)
227{
228 IDirect3DSurface9 *surface = NULL;
229
230 if (mTexture)
231 {
232 HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
233 ASSERT(SUCCEEDED(result));
234
235 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
236 if (level != 0 && isManaged() && dirty)
237 {
238 mTexture->AddDirtyRect(NULL);
239 }
240 }
241
242 return surface;
243}
244
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000245void TextureStorage2D::generateMipmap(int level)
246{
247 IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
248 IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
249
250 if (upper != NULL && lower != NULL)
251 {
252 getBlitter()->boxFilter(upper, lower);
253 }
254
255 if (upper != NULL) upper->Release();
256 if (lower != NULL) lower->Release();
257}
258
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000259IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
260{
261 return mTexture;
262}
263
264unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
265{
266 return mRenderTargetSerial;
267}
268
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000269TextureStorageCubeMap::TextureStorageCubeMap(rx::Renderer9 *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
270 : TextureStorage(renderer, GetTextureUsage(renderer->ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000271 mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000272{
273 mTexture = NULL;
274 // if the size is not positive this should be treated as an incomplete texture
275 // we handle that here by skipping the d3d texture creation
276 if (size > 0)
277 {
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000278 IDirect3DDevice9 *device = renderer->getDevice();
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000279 int height = size;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000280 MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
281 HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000282 renderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000283
284 if (FAILED(result))
285 {
286 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
287 error(GL_OUT_OF_MEMORY);
288 }
289 }
290}
291
292TextureStorageCubeMap::~TextureStorageCubeMap()
293{
294 if (mTexture)
295 {
296 mTexture->Release();
297 }
298}
299
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000300bool TextureStorageCubeMap::copyToRenderTarget(TextureStorageCubeMap *dest, TextureStorageCubeMap *source)
301{
302 bool result = false;
303
304 if (source && dest)
305 {
306 int levels = source->levelCount();
307 for (int f = 0; f < 6; f++)
308 {
309 for (int i = 0; i < levels; i++)
310 {
311 IDirect3DSurface9 *srcSurf = source->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
312 IDirect3DSurface9 *dstSurf = dest->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
313
314 result = TextureStorage::copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
315
316 if (srcSurf) srcSurf->Release();
317 if (dstSurf) dstSurf->Release();
318
319 if (!result)
320 return false;
321 }
322 }
323 }
324
325 return result;
326}
327
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000328// Increments refcount on surface.
329// caller must Release() the returned surface
330IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
331{
332 IDirect3DSurface9 *surface = NULL;
333
334 if (mTexture)
335 {
336 D3DCUBEMAP_FACES face = es2dx::ConvertCubeFace(faceTarget);
337 HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
338 ASSERT(SUCCEEDED(result));
339
340 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
341 if (level != 0 && isManaged() && dirty)
342 {
343 mTexture->AddDirtyRect(face, NULL);
344 }
345 }
346
347 return surface;
348}
349
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000350void TextureStorageCubeMap::generateMipmap(int face, int level)
351{
352 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false);
353 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
354
355 if (upper != NULL && lower != NULL)
356 {
357 getBlitter()->boxFilter(upper, lower);
358 }
359
360 if (upper != NULL) upper->Release();
361 if (lower != NULL) lower->Release();
362}
363
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000364IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
365{
366 return mTexture;
367}
368
369unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
370{
371 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
372}
373
374}