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