1 //
2 // Copyright 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 // 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/Context.h"
15 #include "libANGLE/Texture.h"
16 #include "libANGLE/formatutils.h"
17 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
18 #include "libANGLE/renderer/d3d/TextureD3D.h"
19 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
20 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
21 #include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
22 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
23 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
24 
25 namespace rx
26 {
TextureStorage9(Renderer9 * renderer,DWORD usage)27 TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage)
28     : mTopLevel(0),
29       mMipLevels(0),
30       mTextureWidth(0),
31       mTextureHeight(0),
32       mInternalFormat(GL_NONE),
33       mTextureFormat(D3DFMT_UNKNOWN),
34       mRenderer(renderer),
35       mD3DUsage(usage),
36       mD3DPool(mRenderer->getTexturePool(usage))
37 {}
38 
~TextureStorage9()39 TextureStorage9::~TextureStorage9() {}
40 
GetTextureUsage(GLenum internalformat,bool renderTarget)41 DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget)
42 {
43     DWORD d3dusage = 0;
44 
45     const gl::InternalFormat &formatInfo     = gl::GetSizedInternalFormatInfo(internalformat);
46     const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
47     if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
48     {
49         d3dusage |= D3DUSAGE_DEPTHSTENCIL;
50     }
51     else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN))
52     {
53         d3dusage |= D3DUSAGE_RENDERTARGET;
54     }
55 
56     return d3dusage;
57 }
58 
isRenderTarget() const59 bool TextureStorage9::isRenderTarget() const
60 {
61     return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
62 }
63 
isManaged() const64 bool TextureStorage9::isManaged() const
65 {
66     return (mD3DPool == D3DPOOL_MANAGED);
67 }
68 
supportsNativeMipmapFunction() const69 bool TextureStorage9::supportsNativeMipmapFunction() const
70 {
71     return false;
72 }
73 
getPool() const74 D3DPOOL TextureStorage9::getPool() const
75 {
76     return mD3DPool;
77 }
78 
getUsage() const79 DWORD TextureStorage9::getUsage() const
80 {
81     return mD3DUsage;
82 }
83 
getTopLevel() const84 int TextureStorage9::getTopLevel() const
85 {
86     return mTopLevel;
87 }
88 
getLevelCount() const89 int TextureStorage9::getLevelCount() const
90 {
91     return static_cast<int>(mMipLevels) - mTopLevel;
92 }
93 
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)94 angle::Result TextureStorage9::setData(const gl::Context *context,
95                                        const gl::ImageIndex &index,
96                                        ImageD3D *image,
97                                        const gl::Box *destBox,
98                                        GLenum type,
99                                        const gl::PixelUnpackState &unpack,
100                                        const uint8_t *pixelData)
101 {
102     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
103     return angle::Result::Stop;
104 }
105 
TextureStorage9_2D(Renderer9 * renderer,SwapChain9 * swapchain)106 TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain)
107     : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
108 {
109     IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
110     mTexture                          = surfaceTexture;
111     mMipLevels                        = surfaceTexture->GetLevelCount();
112 
113     mInternalFormat = swapchain->getRenderTargetInternalFormat();
114 
115     D3DSURFACE_DESC surfaceDesc;
116     surfaceTexture->GetLevelDesc(0, &surfaceDesc);
117     mTextureWidth  = surfaceDesc.Width;
118     mTextureHeight = surfaceDesc.Height;
119     mTextureFormat = surfaceDesc.Format;
120 
121     mRenderTargets.resize(mMipLevels, nullptr);
122 }
123 
TextureStorage9_2D(Renderer9 * renderer,GLenum internalformat,bool renderTarget,GLsizei width,GLsizei height,int levels)124 TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer,
125                                        GLenum internalformat,
126                                        bool renderTarget,
127                                        GLsizei width,
128                                        GLsizei height,
129                                        int levels)
130     : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
131 {
132     mTexture = nullptr;
133 
134     mInternalFormat = internalformat;
135 
136     const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
137     mTextureFormat                           = d3dFormatInfo.texFormat;
138 
139     d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel);
140     mTextureWidth  = width;
141     mTextureHeight = height;
142     mMipLevels     = mTopLevel + levels;
143 
144     mRenderTargets.resize(levels, nullptr);
145 }
146 
~TextureStorage9_2D()147 TextureStorage9_2D::~TextureStorage9_2D()
148 {
149     SafeRelease(mTexture);
150     for (RenderTargetD3D *renderTarget : mRenderTargets)
151     {
152         SafeDelete(renderTarget);
153     }
154 }
155 
156 // Increments refcount on surface.
157 // caller must Release() the returned surface
getSurfaceLevel(const gl::Context * context,gl::TextureTarget target,int level,bool dirty,IDirect3DSurface9 ** outSurface)158 angle::Result TextureStorage9_2D::getSurfaceLevel(const gl::Context *context,
159                                                   gl::TextureTarget target,
160                                                   int level,
161                                                   bool dirty,
162                                                   IDirect3DSurface9 **outSurface)
163 {
164     ASSERT(target == gl::TextureTarget::_2D);
165 
166     IDirect3DBaseTexture9 *baseTexture = nullptr;
167     ANGLE_TRY(getBaseTexture(context, &baseTexture));
168 
169     IDirect3DTexture9 *texture = static_cast<IDirect3DTexture9 *>(baseTexture);
170 
171     HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface);
172     ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture");
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(nullptr);
178     }
179 
180     return angle::Result::Continue;
181 }
182 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)183 angle::Result TextureStorage9_2D::getRenderTarget(const gl::Context *context,
184                                                   const gl::ImageIndex &index,
185                                                   GLsizei samples,
186                                                   RenderTargetD3D **outRT)
187 {
188     ASSERT(index.getLevelIndex() < getLevelCount());
189 
190     if (!mRenderTargets[index.getLevelIndex()] && isRenderTarget())
191     {
192         IDirect3DBaseTexture9 *baseTexture = nullptr;
193         ANGLE_TRY(getBaseTexture(context, &baseTexture));
194 
195         IDirect3DSurface9 *surface = nullptr;
196         ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, index.getLevelIndex(), false,
197                                   &surface));
198 
199         size_t textureMipLevel = mTopLevel + index.getLevelIndex();
200         size_t mipWidth        = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u);
201         size_t mipHeight       = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u);
202 
203         baseTexture->AddRef();
204         mRenderTargets[index.getLevelIndex()] = new TextureRenderTarget9(
205             baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth),
206             static_cast<GLsizei>(mipHeight), 1, 0);
207     }
208 
209     ASSERT(outRT);
210     *outRT = mRenderTargets[index.getLevelIndex()];
211     return angle::Result::Continue;
212 }
213 
generateMipmap(const gl::Context * context,const gl::ImageIndex & sourceIndex,const gl::ImageIndex & destIndex)214 angle::Result TextureStorage9_2D::generateMipmap(const gl::Context *context,
215                                                  const gl::ImageIndex &sourceIndex,
216                                                  const gl::ImageIndex &destIndex)
217 {
218     angle::ComPtr<IDirect3DSurface9> upper = nullptr;
219     ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, sourceIndex.getLevelIndex(), false,
220                               &upper));
221 
222     angle::ComPtr<IDirect3DSurface9> lower = nullptr;
223     ANGLE_TRY(
224         getSurfaceLevel(context, gl::TextureTarget::_2D, destIndex.getLevelIndex(), true, &lower));
225 
226     ASSERT(upper && lower);
227     return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get());
228 }
229 
getBaseTexture(const gl::Context * context,IDirect3DBaseTexture9 ** outTexture)230 angle::Result TextureStorage9_2D::getBaseTexture(const gl::Context *context,
231                                                  IDirect3DBaseTexture9 **outTexture)
232 {
233     // if the width or height is not positive this should be treated as an incomplete texture
234     // we handle that here by skipping the d3d texture creation
235     if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0)
236     {
237         ASSERT(mMipLevels > 0);
238 
239         IDirect3DDevice9 *device = mRenderer->getDevice();
240         HRESULT result           = device->CreateTexture(static_cast<unsigned int>(mTextureWidth),
241                                                static_cast<unsigned int>(mTextureHeight),
242                                                static_cast<unsigned int>(mMipLevels), getUsage(),
243                                                mTextureFormat, getPool(), &mTexture, nullptr);
244         ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create 2D storage texture");
245     }
246 
247     *outTexture = mTexture;
248     return angle::Result::Continue;
249 }
250 
copyToStorage(const gl::Context * context,TextureStorage * destStorage)251 angle::Result TextureStorage9_2D::copyToStorage(const gl::Context *context,
252                                                 TextureStorage *destStorage)
253 {
254     ASSERT(destStorage);
255 
256     TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage);
257 
258     int levels = getLevelCount();
259     for (int i = 0; i < levels; ++i)
260     {
261         angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr;
262         ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, i, false, &srcSurf));
263 
264         angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr;
265         ANGLE_TRY(dest9->getSurfaceLevel(context, gl::TextureTarget::_2D, i, true, &dstSurf));
266 
267         ANGLE_TRY(
268             mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged()));
269     }
270 
271     return angle::Result::Continue;
272 }
273 
TextureStorage9_EGLImage(Renderer9 * renderer,EGLImageD3D * image,RenderTarget9 * renderTarget9)274 TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer,
275                                                    EGLImageD3D *image,
276                                                    RenderTarget9 *renderTarget9)
277     : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image)
278 {
279     mInternalFormat = renderTarget9->getInternalFormat();
280     mTextureFormat  = renderTarget9->getD3DFormat();
281     mTextureWidth   = renderTarget9->getWidth();
282     mTextureHeight  = renderTarget9->getHeight();
283     mTopLevel       = static_cast<int>(renderTarget9->getTextureLevel());
284     mMipLevels      = mTopLevel + 1;
285 }
286 
~TextureStorage9_EGLImage()287 TextureStorage9_EGLImage::~TextureStorage9_EGLImage() {}
288 
getSurfaceLevel(const gl::Context * context,gl::TextureTarget target,int level,bool,IDirect3DSurface9 ** outSurface)289 angle::Result TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *context,
290                                                         gl::TextureTarget target,
291                                                         int level,
292                                                         bool,
293                                                         IDirect3DSurface9 **outSurface)
294 {
295     ASSERT(target == gl::TextureTarget::_2D);
296     ASSERT(level == 0);
297 
298     RenderTargetD3D *renderTargetD3D = nullptr;
299     ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D));
300 
301     RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
302 
303     *outSurface = renderTarget9->getSurface();
304     return angle::Result::Continue;
305 }
306 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)307 angle::Result TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context,
308                                                         const gl::ImageIndex &index,
309                                                         GLsizei samples,
310                                                         RenderTargetD3D **outRT)
311 {
312     ASSERT(!index.hasLayer());
313     ASSERT(index.getLevelIndex() == 0);
314     ASSERT(samples == 0);
315 
316     return mImage->getRenderTarget(context, outRT);
317 }
318 
getBaseTexture(const gl::Context * context,IDirect3DBaseTexture9 ** outTexture)319 angle::Result TextureStorage9_EGLImage::getBaseTexture(const gl::Context *context,
320                                                        IDirect3DBaseTexture9 **outTexture)
321 {
322     RenderTargetD3D *renderTargetD3D = nullptr;
323     ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D));
324 
325     RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
326     *outTexture                  = renderTarget9->getTexture();
327     ASSERT(*outTexture != nullptr);
328 
329     return angle::Result::Continue;
330 }
331 
generateMipmap(const gl::Context * context,const gl::ImageIndex &,const gl::ImageIndex &)332 angle::Result TextureStorage9_EGLImage::generateMipmap(const gl::Context *context,
333                                                        const gl::ImageIndex &,
334                                                        const gl::ImageIndex &)
335 {
336     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
337     return angle::Result::Stop;
338 }
339 
copyToStorage(const gl::Context * context,TextureStorage * destStorage)340 angle::Result TextureStorage9_EGLImage::copyToStorage(const gl::Context *context,
341                                                       TextureStorage *destStorage)
342 {
343     ASSERT(destStorage);
344     ASSERT(getLevelCount() == 1);
345 
346     TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage);
347 
348     IDirect3DBaseTexture9 *destBaseTexture9 = nullptr;
349     ANGLE_TRY(dest9->getBaseTexture(context, &destBaseTexture9));
350 
351     IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9);
352 
353     angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
354     HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface);
355     ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture");
356 
357     RenderTargetD3D *sourceRenderTarget = nullptr;
358     ANGLE_TRY(mImage->getRenderTarget(context, &sourceRenderTarget));
359 
360     RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget);
361     ANGLE_TRY(mRenderer->copyToRenderTarget(context, destSurface.Get(),
362                                             sourceRenderTarget9->getSurface(), isManaged()));
363 
364     if (destStorage->getTopLevel() != 0)
365     {
366         destTexture9->AddDirtyRect(nullptr);
367     }
368 
369     return angle::Result::Continue;
370 }
371 
TextureStorage9_Cube(Renderer9 * renderer,GLenum internalformat,bool renderTarget,int size,int levels,bool hintLevelZeroOnly)372 TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer,
373                                            GLenum internalformat,
374                                            bool renderTarget,
375                                            int size,
376                                            int levels,
377                                            bool hintLevelZeroOnly)
378     : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
379 {
380     mTexture = nullptr;
381     for (size_t i = 0; i < gl::kCubeFaceCount; ++i)
382     {
383         mRenderTarget[i] = nullptr;
384     }
385 
386     mInternalFormat = internalformat;
387 
388     const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
389     mTextureFormat                           = d3dFormatInfo.texFormat;
390 
391     int height = size;
392     d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel);
393     mTextureWidth  = size;
394     mTextureHeight = size;
395     mMipLevels     = mTopLevel + levels;
396 }
397 
~TextureStorage9_Cube()398 TextureStorage9_Cube::~TextureStorage9_Cube()
399 {
400     SafeRelease(mTexture);
401 
402     for (size_t i = 0; i < gl::kCubeFaceCount; ++i)
403     {
404         SafeDelete(mRenderTarget[i]);
405     }
406 }
407 
408 // Increments refcount on surface.
409 // caller must Release() the returned surface
getSurfaceLevel(const gl::Context * context,gl::TextureTarget target,int level,bool dirty,IDirect3DSurface9 ** outSurface)410 angle::Result TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context,
411                                                     gl::TextureTarget target,
412                                                     int level,
413                                                     bool dirty,
414                                                     IDirect3DSurface9 **outSurface)
415 {
416     IDirect3DBaseTexture9 *baseTexture = nullptr;
417     ANGLE_TRY(getBaseTexture(context, &baseTexture));
418 
419     IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9 *>(baseTexture);
420 
421     D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target);
422     HRESULT result        = texture->GetCubeMapSurface(face, level, outSurface);
423     ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture");
424 
425     // With managed textures the driver needs to be informed of updates to the lower mipmap levels
426     if (level != 0 && isManaged() && dirty)
427     {
428         texture->AddDirtyRect(face, nullptr);
429     }
430 
431     return angle::Result::Continue;
432 }
433 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)434 angle::Result TextureStorage9_Cube::getRenderTarget(const gl::Context *context,
435                                                     const gl::ImageIndex &index,
436                                                     GLsizei samples,
437                                                     RenderTargetD3D **outRT)
438 {
439     ASSERT(outRT);
440     ASSERT(index.getLevelIndex() == 0);
441     ASSERT(samples == 0);
442 
443     ASSERT(index.getType() == gl::TextureType::CubeMap &&
444            gl::IsCubeMapFaceTarget(index.getTarget()));
445     const size_t renderTargetIndex = index.cubeMapFaceIndex();
446 
447     if (mRenderTarget[renderTargetIndex] == nullptr && isRenderTarget())
448     {
449         IDirect3DBaseTexture9 *baseTexture = nullptr;
450         ANGLE_TRY(getBaseTexture(context, &baseTexture));
451 
452         IDirect3DSurface9 *surface = nullptr;
453         ANGLE_TRY(getSurfaceLevel(context, index.getTarget(), mTopLevel + index.getLevelIndex(),
454                                   false, &surface));
455 
456         baseTexture->AddRef();
457         mRenderTarget[renderTargetIndex] = new TextureRenderTarget9(
458             baseTexture, mTopLevel + index.getLevelIndex(), surface, mInternalFormat,
459             static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0);
460     }
461 
462     *outRT = mRenderTarget[renderTargetIndex];
463     return angle::Result::Continue;
464 }
465 
generateMipmap(const gl::Context * context,const gl::ImageIndex & sourceIndex,const gl::ImageIndex & destIndex)466 angle::Result TextureStorage9_Cube::generateMipmap(const gl::Context *context,
467                                                    const gl::ImageIndex &sourceIndex,
468                                                    const gl::ImageIndex &destIndex)
469 {
470     angle::ComPtr<IDirect3DSurface9> upper = nullptr;
471     ANGLE_TRY(getSurfaceLevel(context, sourceIndex.getTarget(), sourceIndex.getLevelIndex(), false,
472                               &upper));
473 
474     angle::ComPtr<IDirect3DSurface9> lower = nullptr;
475     ANGLE_TRY(
476         getSurfaceLevel(context, destIndex.getTarget(), destIndex.getLevelIndex(), true, &lower));
477 
478     ASSERT(upper && lower);
479     return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get());
480 }
481 
getBaseTexture(const gl::Context * context,IDirect3DBaseTexture9 ** outTexture)482 angle::Result TextureStorage9_Cube::getBaseTexture(const gl::Context *context,
483                                                    IDirect3DBaseTexture9 **outTexture)
484 {
485     // if the size is not positive this should be treated as an incomplete texture
486     // we handle that here by skipping the d3d texture creation
487     if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0)
488     {
489         ASSERT(mMipLevels > 0);
490         ASSERT(mTextureWidth == mTextureHeight);
491 
492         IDirect3DDevice9 *device = mRenderer->getDevice();
493         HRESULT result           = device->CreateCubeTexture(
494             static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels),
495             getUsage(), mTextureFormat, getPool(), &mTexture, nullptr);
496         ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create cube storage texture");
497     }
498 
499     *outTexture = mTexture;
500     return angle::Result::Continue;
501 }
502 
copyToStorage(const gl::Context * context,TextureStorage * destStorage)503 angle::Result TextureStorage9_Cube::copyToStorage(const gl::Context *context,
504                                                   TextureStorage *destStorage)
505 {
506     ASSERT(destStorage);
507 
508     TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage);
509 
510     int levels = getLevelCount();
511     for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
512     {
513         for (int i = 0; i < levels; i++)
514         {
515             angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr;
516             ANGLE_TRY(getSurfaceLevel(context, face, i, false, &srcSurf));
517 
518             angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr;
519             ANGLE_TRY(dest9->getSurfaceLevel(context, face, i, true, &dstSurf));
520 
521             ANGLE_TRY(
522                 mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged()));
523         }
524     }
525 
526     return angle::Result::Continue;
527 }
528 }  // namespace rx
529