1 //
2 // Copyright (c) 2012-2014 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 // TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived
8 // classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
9 // D3D9 texture.
10
11 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
12
13 #include "libANGLE/formatutils.h"
14 #include "libANGLE/Texture.h"
15 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
16 #include "libANGLE/renderer/d3d/TextureD3D.h"
17 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
18 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
19 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
20 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
21 #include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
22
23 namespace rx
24 {
TextureStorage9(Renderer9 * renderer,DWORD usage)25 TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage)
26 : mTopLevel(0),
27 mMipLevels(0),
28 mTextureWidth(0),
29 mTextureHeight(0),
30 mInternalFormat(GL_NONE),
31 mTextureFormat(D3DFMT_UNKNOWN),
32 mRenderer(renderer),
33 mD3DUsage(usage),
34 mD3DPool(mRenderer->getTexturePool(usage))
35 {
36 }
37
~TextureStorage9()38 TextureStorage9::~TextureStorage9()
39 {
40 }
41
GetTextureUsage(GLenum internalformat,bool renderTarget)42 DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget)
43 {
44 DWORD d3dusage = 0;
45
46 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
47 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
48 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
49 {
50 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
51 }
52 else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN))
53 {
54 d3dusage |= D3DUSAGE_RENDERTARGET;
55 }
56
57 return d3dusage;
58 }
59
60
isRenderTarget() const61 bool TextureStorage9::isRenderTarget() const
62 {
63 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
64 }
65
isManaged() const66 bool TextureStorage9::isManaged() const
67 {
68 return (mD3DPool == D3DPOOL_MANAGED);
69 }
70
supportsNativeMipmapFunction() const71 bool TextureStorage9::supportsNativeMipmapFunction() const
72 {
73 return false;
74 }
75
getPool() const76 D3DPOOL TextureStorage9::getPool() const
77 {
78 return mD3DPool;
79 }
80
getUsage() const81 DWORD TextureStorage9::getUsage() const
82 {
83 return mD3DUsage;
84 }
85
getTopLevel() const86 int TextureStorage9::getTopLevel() const
87 {
88 return mTopLevel;
89 }
90
getLevelCount() const91 int TextureStorage9::getLevelCount() const
92 {
93 return static_cast<int>(mMipLevels) - mTopLevel;
94 }
95
setData(const gl::ImageIndex & index,ImageD3D * image,const gl::Box * destBox,GLenum type,const gl::PixelUnpackState & unpack,const uint8_t * pixelData)96 gl::Error TextureStorage9::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
97 const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
98 {
99 UNREACHABLE();
100 return gl::Error(GL_INVALID_OPERATION);
101 }
102
TextureStorage9_2D(Renderer9 * renderer,SwapChain9 * swapchain)103 TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain)
104 : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
105 {
106 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
107 mTexture = surfaceTexture;
108 mMipLevels = surfaceTexture->GetLevelCount();
109
110 mInternalFormat = swapchain->getRenderTargetInternalFormat();
111
112 D3DSURFACE_DESC surfaceDesc;
113 surfaceTexture->GetLevelDesc(0, &surfaceDesc);
114 mTextureWidth = surfaceDesc.Width;
115 mTextureHeight = surfaceDesc.Height;
116 mTextureFormat = surfaceDesc.Format;
117
118 mRenderTargets.resize(mMipLevels, nullptr);
119 }
120
TextureStorage9_2D(Renderer9 * renderer,GLenum internalformat,bool renderTarget,GLsizei width,GLsizei height,int levels)121 TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels)
122 : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
123 {
124 mTexture = NULL;
125
126 mInternalFormat = internalformat;
127
128 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
129 mTextureFormat = d3dFormatInfo.texFormat;
130
131 d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel);
132 mTextureWidth = width;
133 mTextureHeight = height;
134 mMipLevels = mTopLevel + levels;
135
136 mRenderTargets.resize(levels, nullptr);
137 }
138
~TextureStorage9_2D()139 TextureStorage9_2D::~TextureStorage9_2D()
140 {
141 SafeRelease(mTexture);
142 for (auto &renderTarget : mRenderTargets)
143 {
144 SafeDelete(renderTarget);
145 }
146 }
147
148 // Increments refcount on surface.
149 // caller must Release() the returned surface
getSurfaceLevel(GLenum target,int level,bool dirty,IDirect3DSurface9 ** outSurface)150 gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target,
151 int level,
152 bool dirty,
153 IDirect3DSurface9 **outSurface)
154 {
155 ASSERT(target == GL_TEXTURE_2D);
156
157 IDirect3DBaseTexture9 *baseTexture = NULL;
158 gl::Error error = getBaseTexture(&baseTexture);
159 if (error.isError())
160 {
161 return error;
162 }
163
164 IDirect3DTexture9 *texture = static_cast<IDirect3DTexture9*>(baseTexture);
165
166 HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface);
167
168 ASSERT(SUCCEEDED(result));
169 if (FAILED(result))
170 {
171 return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result);
172 }
173
174 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
175 if (level + mTopLevel != 0 && isManaged() && dirty)
176 {
177 texture->AddDirtyRect(NULL);
178 }
179
180 return gl::Error(GL_NO_ERROR);
181 }
182
getRenderTarget(const gl::ImageIndex & index,RenderTargetD3D ** outRT)183 gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
184 {
185 ASSERT(index.mipIndex < getLevelCount());
186
187 if (!mRenderTargets[index.mipIndex] && isRenderTarget())
188 {
189 IDirect3DBaseTexture9 *baseTexture = NULL;
190 gl::Error error = getBaseTexture(&baseTexture);
191 if (error.isError())
192 {
193 return error;
194 }
195
196 IDirect3DSurface9 *surface = NULL;
197 error = getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, false, &surface);
198 if (error.isError())
199 {
200 return error;
201 }
202
203 size_t textureMipLevel = mTopLevel + index.mipIndex;
204 size_t mipWidth = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u);
205 size_t mipHeight = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u);
206
207 baseTexture->AddRef();
208 mRenderTargets[index.mipIndex] = new TextureRenderTarget9(
209 baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth),
210 static_cast<GLsizei>(mipHeight), 1, 0);
211 }
212
213 ASSERT(outRT);
214 *outRT = mRenderTargets[index.mipIndex];
215 return gl::Error(GL_NO_ERROR);
216 }
217
generateMipmap(const gl::ImageIndex & sourceIndex,const gl::ImageIndex & destIndex)218 gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
219 {
220 IDirect3DSurface9 *upper = NULL;
221 gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper);
222 if (error.isError())
223 {
224 return error;
225 }
226
227 IDirect3DSurface9 *lower = NULL;
228 error = getSurfaceLevel(GL_TEXTURE_2D, destIndex.mipIndex, true, &lower);
229 if (error.isError())
230 {
231 SafeRelease(upper);
232 return error;
233 }
234
235 ASSERT(upper && lower);
236 error = mRenderer->boxFilter(upper, lower);
237
238 SafeRelease(upper);
239 SafeRelease(lower);
240
241 return error;
242 }
243
getBaseTexture(IDirect3DBaseTexture9 ** outTexture)244 gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
245 {
246 // if the width or height is not positive this should be treated as an incomplete texture
247 // we handle that here by skipping the d3d texture creation
248 if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
249 {
250 ASSERT(mMipLevels > 0);
251
252 IDirect3DDevice9 *device = mRenderer->getDevice();
253 HRESULT result = device->CreateTexture(static_cast<unsigned int>(mTextureWidth),
254 static_cast<unsigned int>(mTextureHeight),
255 static_cast<unsigned int>(mMipLevels), getUsage(),
256 mTextureFormat, getPool(), &mTexture, NULL);
257
258 if (FAILED(result))
259 {
260 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
261 return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result);
262 }
263 }
264
265 *outTexture = mTexture;
266 return gl::Error(GL_NO_ERROR);
267 }
268
copyToStorage(TextureStorage * destStorage)269 gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage)
270 {
271 ASSERT(destStorage);
272
273 TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage);
274
275 int levels = getLevelCount();
276 for (int i = 0; i < levels; ++i)
277 {
278 IDirect3DSurface9 *srcSurf = NULL;
279 gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, i, false, &srcSurf);
280 if (error.isError())
281 {
282 return error;
283 }
284
285 IDirect3DSurface9 *dstSurf = NULL;
286 error = dest9->getSurfaceLevel(GL_TEXTURE_2D, i, true, &dstSurf);
287 if (error.isError())
288 {
289 SafeRelease(srcSurf);
290 return error;
291 }
292
293 error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged());
294
295 SafeRelease(srcSurf);
296 SafeRelease(dstSurf);
297
298 if (error.isError())
299 {
300 return error;
301 }
302 }
303
304 return gl::Error(GL_NO_ERROR);
305 }
306
TextureStorage9_EGLImage(Renderer9 * renderer,EGLImageD3D * image,RenderTarget9 * renderTarget9)307 TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer,
308 EGLImageD3D *image,
309 RenderTarget9 *renderTarget9)
310 : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image)
311 {
312 mInternalFormat = renderTarget9->getInternalFormat();
313 mTextureFormat = renderTarget9->getD3DFormat();
314 mTextureWidth = renderTarget9->getWidth();
315 mTextureHeight = renderTarget9->getHeight();
316 mTopLevel = static_cast<int>(renderTarget9->getTextureLevel());
317 mMipLevels = mTopLevel + 1;
318 }
319
~TextureStorage9_EGLImage()320 TextureStorage9_EGLImage::~TextureStorage9_EGLImage()
321 {
322 }
323
getSurfaceLevel(GLenum target,int level,bool,IDirect3DSurface9 ** outSurface)324 gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target,
325 int level,
326 bool,
327 IDirect3DSurface9 **outSurface)
328 {
329 ASSERT(target == GL_TEXTURE_2D);
330 ASSERT(level == 0);
331
332 RenderTargetD3D *renderTargetD3D = nullptr;
333 gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
334 if (error.isError())
335 {
336 return error;
337 }
338
339 RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
340
341 *outSurface = renderTarget9->getSurface();
342 return gl::Error(GL_NO_ERROR);
343 }
344
getRenderTarget(const gl::ImageIndex & index,RenderTargetD3D ** outRT)345 gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::ImageIndex &index,
346 RenderTargetD3D **outRT)
347 {
348 ASSERT(!index.hasLayer());
349 ASSERT(index.mipIndex == 0);
350
351 return mImage->getRenderTarget(outRT);
352 }
353
getBaseTexture(IDirect3DBaseTexture9 ** outTexture)354 gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
355 {
356 RenderTargetD3D *renderTargetD3D = nullptr;
357 gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
358 if (error.isError())
359 {
360 return error;
361 }
362
363 RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
364 *outTexture = renderTarget9->getTexture();
365 ASSERT(*outTexture != nullptr);
366
367 return gl::Error(GL_NO_ERROR);
368 }
369
generateMipmap(const gl::ImageIndex &,const gl::ImageIndex &)370 gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::ImageIndex &, const gl::ImageIndex &)
371 {
372 UNREACHABLE();
373 return gl::Error(GL_INVALID_OPERATION);
374 }
375
copyToStorage(TextureStorage * destStorage)376 gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage)
377 {
378 ASSERT(destStorage);
379 ASSERT(getLevelCount() == 1);
380
381 TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage);
382
383 IDirect3DBaseTexture9 *destBaseTexture9 = nullptr;
384 gl::Error error = dest9->getBaseTexture(&destBaseTexture9);
385 if (error.isError())
386 {
387 return error;
388 }
389
390 IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9);
391
392 IDirect3DSurface9 *destSurface = nullptr;
393 HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface);
394 if (FAILED(result))
395 {
396 return gl::Error(GL_OUT_OF_MEMORY,
397 "Failed to get the surface from a texture, result: 0x%X.", result);
398 }
399
400 RenderTargetD3D *sourceRenderTarget = nullptr;
401 error = mImage->getRenderTarget(&sourceRenderTarget);
402 if (error.isError())
403 {
404 SafeRelease(destSurface);
405 return error;
406 }
407
408 RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget);
409 error =
410 mRenderer->copyToRenderTarget(destSurface, sourceRenderTarget9->getSurface(), isManaged());
411 if (error.isError())
412 {
413 SafeRelease(destSurface);
414 return error;
415 }
416
417 if (destStorage->getTopLevel() != 0)
418 {
419 destTexture9->AddDirtyRect(nullptr);
420 }
421
422 SafeRelease(destSurface);
423 return gl::Error(GL_NO_ERROR);
424 }
425
TextureStorage9_Cube(Renderer9 * renderer,GLenum internalformat,bool renderTarget,int size,int levels,bool hintLevelZeroOnly)426 TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
427 : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
428 {
429 mTexture = NULL;
430 for (size_t i = 0; i < CUBE_FACE_COUNT; ++i)
431 {
432 mRenderTarget[i] = NULL;
433 }
434
435 mInternalFormat = internalformat;
436
437 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
438 mTextureFormat = d3dFormatInfo.texFormat;
439
440 int height = size;
441 d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel);
442 mTextureWidth = size;
443 mTextureHeight = size;
444 mMipLevels = mTopLevel + levels;
445 }
446
~TextureStorage9_Cube()447 TextureStorage9_Cube::~TextureStorage9_Cube()
448 {
449 SafeRelease(mTexture);
450
451 for (size_t i = 0; i < CUBE_FACE_COUNT; ++i)
452 {
453 SafeDelete(mRenderTarget[i]);
454 }
455 }
456
457 // Increments refcount on surface.
458 // caller must Release() the returned surface
getSurfaceLevel(GLenum target,int level,bool dirty,IDirect3DSurface9 ** outSurface)459 gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target,
460 int level,
461 bool dirty,
462 IDirect3DSurface9 **outSurface)
463 {
464 IDirect3DBaseTexture9 *baseTexture = NULL;
465 gl::Error error = getBaseTexture(&baseTexture);
466 if (error.isError())
467 {
468 return error;
469 }
470
471 IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9*>(baseTexture);
472
473 D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target);
474 HRESULT result = texture->GetCubeMapSurface(face, level, outSurface);
475
476 ASSERT(SUCCEEDED(result));
477 if (FAILED(result))
478 {
479 return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result);
480 }
481
482 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
483 if (level != 0 && isManaged() && dirty)
484 {
485 texture->AddDirtyRect(face, NULL);
486 }
487
488 return gl::Error(GL_NO_ERROR);
489 }
490
getRenderTarget(const gl::ImageIndex & index,RenderTargetD3D ** outRT)491 gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
492 {
493 ASSERT(outRT);
494 ASSERT(index.mipIndex == 0);
495 ASSERT(index.layerIndex >= 0 && static_cast<size_t>(index.layerIndex) < CUBE_FACE_COUNT);
496
497 if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget())
498 {
499 IDirect3DBaseTexture9 *baseTexture = NULL;
500 gl::Error error = getBaseTexture(&baseTexture);
501 if (error.isError())
502 {
503 return error;
504 }
505
506 IDirect3DSurface9 *surface = NULL;
507 error = getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex,
508 mTopLevel + index.mipIndex, false, &surface);
509 if (error.isError())
510 {
511 return error;
512 }
513
514 baseTexture->AddRef();
515 mRenderTarget[index.layerIndex] = new TextureRenderTarget9(
516 baseTexture, mTopLevel + index.mipIndex, surface, mInternalFormat,
517 static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0);
518 }
519
520 *outRT = mRenderTarget[index.layerIndex];
521 return gl::Error(GL_NO_ERROR);
522 }
523
generateMipmap(const gl::ImageIndex & sourceIndex,const gl::ImageIndex & destIndex)524 gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
525 {
526 IDirect3DSurface9 *upper = NULL;
527 gl::Error error = getSurfaceLevel(sourceIndex.type, sourceIndex.mipIndex, false, &upper);
528 if (error.isError())
529 {
530 return error;
531 }
532
533 IDirect3DSurface9 *lower = NULL;
534 error = getSurfaceLevel(destIndex.type, destIndex.mipIndex, true, &lower);
535 if (error.isError())
536 {
537 SafeRelease(upper);
538 return error;
539 }
540
541 ASSERT(upper && lower);
542 error = mRenderer->boxFilter(upper, lower);
543
544 SafeRelease(upper);
545 SafeRelease(lower);
546
547 return error;
548 }
549
getBaseTexture(IDirect3DBaseTexture9 ** outTexture)550 gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
551 {
552 // if the size is not positive this should be treated as an incomplete texture
553 // we handle that here by skipping the d3d texture creation
554 if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
555 {
556 ASSERT(mMipLevels > 0);
557 ASSERT(mTextureWidth == mTextureHeight);
558
559 IDirect3DDevice9 *device = mRenderer->getDevice();
560 HRESULT result = device->CreateCubeTexture(
561 static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels),
562 getUsage(), mTextureFormat, getPool(), &mTexture, NULL);
563
564 if (FAILED(result))
565 {
566 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
567 return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result);
568 }
569 }
570
571 *outTexture = mTexture;
572 return gl::Error(GL_NO_ERROR);
573 }
574
copyToStorage(TextureStorage * destStorage)575 gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage)
576 {
577 ASSERT(destStorage);
578
579 TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage);
580
581 int levels = getLevelCount();
582 for (int f = 0; f < static_cast<int>(CUBE_FACE_COUNT); f++)
583 {
584 for (int i = 0; i < levels; i++)
585 {
586 IDirect3DSurface9 *srcSurf = NULL;
587 gl::Error error =
588 getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf);
589 if (error.isError())
590 {
591 return error;
592 }
593
594 IDirect3DSurface9 *dstSurf = NULL;
595 error = dest9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf);
596 if (error.isError())
597 {
598 SafeRelease(srcSurf);
599 return error;
600 }
601
602 error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged());
603
604 SafeRelease(srcSurf);
605 SafeRelease(dstSurf);
606
607 if (error.isError())
608 {
609 return error;
610 }
611 }
612 }
613
614 return gl::Error(GL_NO_ERROR);
615 }
616
617 }
618