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