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 
findRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT) const183 angle::Result TextureStorage9_2D::findRenderTarget(const gl::Context *context,
184                                                    const gl::ImageIndex &index,
185                                                    GLsizei samples,
186                                                    RenderTargetD3D **outRT) const
187 {
188     ASSERT(index.getLevelIndex() < getLevelCount());
189 
190     ASSERT(outRT);
191     *outRT = mRenderTargets[index.getLevelIndex()];
192     return angle::Result::Continue;
193 }
194 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)195 angle::Result TextureStorage9_2D::getRenderTarget(const gl::Context *context,
196                                                   const gl::ImageIndex &index,
197                                                   GLsizei samples,
198                                                   RenderTargetD3D **outRT)
199 {
200     ASSERT(index.getLevelIndex() < getLevelCount());
201 
202     if (!mRenderTargets[index.getLevelIndex()] && isRenderTarget())
203     {
204         IDirect3DBaseTexture9 *baseTexture = nullptr;
205         ANGLE_TRY(getBaseTexture(context, &baseTexture));
206 
207         IDirect3DSurface9 *surface = nullptr;
208         ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, index.getLevelIndex(), false,
209                                   &surface));
210 
211         size_t textureMipLevel = mTopLevel + index.getLevelIndex();
212         size_t mipWidth        = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u);
213         size_t mipHeight       = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u);
214 
215         baseTexture->AddRef();
216         mRenderTargets[index.getLevelIndex()] = new TextureRenderTarget9(
217             baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth),
218             static_cast<GLsizei>(mipHeight), 1, 0);
219     }
220 
221     ASSERT(outRT);
222     *outRT = mRenderTargets[index.getLevelIndex()];
223     return angle::Result::Continue;
224 }
225 
generateMipmap(const gl::Context * context,const gl::ImageIndex & sourceIndex,const gl::ImageIndex & destIndex)226 angle::Result TextureStorage9_2D::generateMipmap(const gl::Context *context,
227                                                  const gl::ImageIndex &sourceIndex,
228                                                  const gl::ImageIndex &destIndex)
229 {
230     angle::ComPtr<IDirect3DSurface9> upper = nullptr;
231     ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, sourceIndex.getLevelIndex(), false,
232                               &upper));
233 
234     angle::ComPtr<IDirect3DSurface9> lower = nullptr;
235     ANGLE_TRY(
236         getSurfaceLevel(context, gl::TextureTarget::_2D, destIndex.getLevelIndex(), true, &lower));
237 
238     ASSERT(upper && lower);
239     return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get());
240 }
241 
getBaseTexture(const gl::Context * context,IDirect3DBaseTexture9 ** outTexture)242 angle::Result TextureStorage9_2D::getBaseTexture(const gl::Context *context,
243                                                  IDirect3DBaseTexture9 **outTexture)
244 {
245     // if the width or height is not positive this should be treated as an incomplete texture
246     // we handle that here by skipping the d3d texture creation
247     if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0)
248     {
249         ASSERT(mMipLevels > 0);
250 
251         IDirect3DDevice9 *device = mRenderer->getDevice();
252         HRESULT result           = device->CreateTexture(static_cast<unsigned int>(mTextureWidth),
253                                                static_cast<unsigned int>(mTextureHeight),
254                                                static_cast<unsigned int>(mMipLevels), getUsage(),
255                                                mTextureFormat, getPool(), &mTexture, nullptr);
256         ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create 2D storage texture");
257     }
258 
259     *outTexture = mTexture;
260     return angle::Result::Continue;
261 }
262 
copyToStorage(const gl::Context * context,TextureStorage * destStorage)263 angle::Result TextureStorage9_2D::copyToStorage(const gl::Context *context,
264                                                 TextureStorage *destStorage)
265 {
266     ASSERT(destStorage);
267 
268     TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage);
269 
270     int levels = getLevelCount();
271     for (int i = 0; i < levels; ++i)
272     {
273         angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr;
274         ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, i, false, &srcSurf));
275 
276         angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr;
277         ANGLE_TRY(dest9->getSurfaceLevel(context, gl::TextureTarget::_2D, i, true, &dstSurf));
278 
279         ANGLE_TRY(
280             mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged()));
281     }
282 
283     return angle::Result::Continue;
284 }
285 
TextureStorage9_EGLImage(Renderer9 * renderer,EGLImageD3D * image,RenderTarget9 * renderTarget9)286 TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer,
287                                                    EGLImageD3D *image,
288                                                    RenderTarget9 *renderTarget9)
289     : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image)
290 {
291     mInternalFormat = renderTarget9->getInternalFormat();
292     mTextureFormat  = renderTarget9->getD3DFormat();
293     mTextureWidth   = renderTarget9->getWidth();
294     mTextureHeight  = renderTarget9->getHeight();
295     mTopLevel       = static_cast<int>(renderTarget9->getTextureLevel());
296     mMipLevels      = mTopLevel + 1;
297 }
298 
~TextureStorage9_EGLImage()299 TextureStorage9_EGLImage::~TextureStorage9_EGLImage() {}
300 
getSurfaceLevel(const gl::Context * context,gl::TextureTarget target,int level,bool,IDirect3DSurface9 ** outSurface)301 angle::Result TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *context,
302                                                         gl::TextureTarget target,
303                                                         int level,
304                                                         bool,
305                                                         IDirect3DSurface9 **outSurface)
306 {
307     ASSERT(target == gl::TextureTarget::_2D);
308     ASSERT(level == 0);
309 
310     RenderTargetD3D *renderTargetD3D = nullptr;
311     ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D));
312 
313     RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
314 
315     *outSurface = renderTarget9->getSurface();
316     return angle::Result::Continue;
317 }
318 
findRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT) const319 angle::Result TextureStorage9_EGLImage::findRenderTarget(const gl::Context *context,
320                                                          const gl::ImageIndex &index,
321                                                          GLsizei samples,
322                                                          RenderTargetD3D **outRT) const
323 {
324     // Since the render target of a EGL image will be updated when orphaning, trying to find a cache
325     // of it can be rarely useful.
326     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
327     return angle::Result::Stop;
328 }
329 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)330 angle::Result TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context,
331                                                         const gl::ImageIndex &index,
332                                                         GLsizei samples,
333                                                         RenderTargetD3D **outRT)
334 {
335     ASSERT(!index.hasLayer());
336     ASSERT(index.getLevelIndex() == 0);
337     ASSERT(samples == 0);
338 
339     return mImage->getRenderTarget(context, outRT);
340 }
341 
getBaseTexture(const gl::Context * context,IDirect3DBaseTexture9 ** outTexture)342 angle::Result TextureStorage9_EGLImage::getBaseTexture(const gl::Context *context,
343                                                        IDirect3DBaseTexture9 **outTexture)
344 {
345     RenderTargetD3D *renderTargetD3D = nullptr;
346     ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D));
347 
348     RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
349     *outTexture                  = renderTarget9->getTexture();
350     ASSERT(*outTexture != nullptr);
351 
352     return angle::Result::Continue;
353 }
354 
generateMipmap(const gl::Context * context,const gl::ImageIndex &,const gl::ImageIndex &)355 angle::Result TextureStorage9_EGLImage::generateMipmap(const gl::Context *context,
356                                                        const gl::ImageIndex &,
357                                                        const gl::ImageIndex &)
358 {
359     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
360     return angle::Result::Stop;
361 }
362 
copyToStorage(const gl::Context * context,TextureStorage * destStorage)363 angle::Result TextureStorage9_EGLImage::copyToStorage(const gl::Context *context,
364                                                       TextureStorage *destStorage)
365 {
366     ASSERT(destStorage);
367     ASSERT(getLevelCount() == 1);
368 
369     TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage);
370 
371     IDirect3DBaseTexture9 *destBaseTexture9 = nullptr;
372     ANGLE_TRY(dest9->getBaseTexture(context, &destBaseTexture9));
373 
374     IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9);
375 
376     angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
377     HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface);
378     ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture");
379 
380     RenderTargetD3D *sourceRenderTarget = nullptr;
381     ANGLE_TRY(mImage->getRenderTarget(context, &sourceRenderTarget));
382 
383     RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget);
384     ANGLE_TRY(mRenderer->copyToRenderTarget(context, destSurface.Get(),
385                                             sourceRenderTarget9->getSurface(), isManaged()));
386 
387     if (destStorage->getTopLevel() != 0)
388     {
389         destTexture9->AddDirtyRect(nullptr);
390     }
391 
392     return angle::Result::Continue;
393 }
394 
TextureStorage9_Cube(Renderer9 * renderer,GLenum internalformat,bool renderTarget,int size,int levels,bool hintLevelZeroOnly)395 TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer,
396                                            GLenum internalformat,
397                                            bool renderTarget,
398                                            int size,
399                                            int levels,
400                                            bool hintLevelZeroOnly)
401     : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
402 {
403     mTexture = nullptr;
404     for (size_t i = 0; i < gl::kCubeFaceCount; ++i)
405     {
406         mRenderTarget[i] = nullptr;
407     }
408 
409     mInternalFormat = internalformat;
410 
411     const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat);
412     mTextureFormat                           = d3dFormatInfo.texFormat;
413 
414     int height = size;
415     d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel);
416     mTextureWidth  = size;
417     mTextureHeight = size;
418     mMipLevels     = mTopLevel + levels;
419 }
420 
~TextureStorage9_Cube()421 TextureStorage9_Cube::~TextureStorage9_Cube()
422 {
423     SafeRelease(mTexture);
424 
425     for (size_t i = 0; i < gl::kCubeFaceCount; ++i)
426     {
427         SafeDelete(mRenderTarget[i]);
428     }
429 }
430 
431 // Increments refcount on surface.
432 // caller must Release() the returned surface
getSurfaceLevel(const gl::Context * context,gl::TextureTarget target,int level,bool dirty,IDirect3DSurface9 ** outSurface)433 angle::Result TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context,
434                                                     gl::TextureTarget target,
435                                                     int level,
436                                                     bool dirty,
437                                                     IDirect3DSurface9 **outSurface)
438 {
439     IDirect3DBaseTexture9 *baseTexture = nullptr;
440     ANGLE_TRY(getBaseTexture(context, &baseTexture));
441 
442     IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9 *>(baseTexture);
443 
444     D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target);
445     HRESULT result        = texture->GetCubeMapSurface(face, level, outSurface);
446     ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture");
447 
448     // With managed textures the driver needs to be informed of updates to the lower mipmap levels
449     if (level != 0 && isManaged() && dirty)
450     {
451         texture->AddDirtyRect(face, nullptr);
452     }
453 
454     return angle::Result::Continue;
455 }
456 
findRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT) const457 angle::Result TextureStorage9_Cube::findRenderTarget(const gl::Context *context,
458                                                      const gl::ImageIndex &index,
459                                                      GLsizei samples,
460                                                      RenderTargetD3D **outRT) const
461 {
462     ASSERT(outRT);
463     ASSERT(index.getLevelIndex() == 0);
464     ASSERT(samples == 0);
465 
466     ASSERT(index.getType() == gl::TextureType::CubeMap &&
467            gl::IsCubeMapFaceTarget(index.getTarget()));
468     const size_t renderTargetIndex = index.cubeMapFaceIndex();
469 
470     *outRT = mRenderTarget[renderTargetIndex];
471     return angle::Result::Continue;
472 }
473 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)474 angle::Result TextureStorage9_Cube::getRenderTarget(const gl::Context *context,
475                                                     const gl::ImageIndex &index,
476                                                     GLsizei samples,
477                                                     RenderTargetD3D **outRT)
478 {
479     ASSERT(outRT);
480     ASSERT(index.getLevelIndex() == 0);
481     ASSERT(samples == 0);
482 
483     ASSERT(index.getType() == gl::TextureType::CubeMap &&
484            gl::IsCubeMapFaceTarget(index.getTarget()));
485     const size_t renderTargetIndex = index.cubeMapFaceIndex();
486 
487     if (mRenderTarget[renderTargetIndex] == nullptr && isRenderTarget())
488     {
489         IDirect3DBaseTexture9 *baseTexture = nullptr;
490         ANGLE_TRY(getBaseTexture(context, &baseTexture));
491 
492         IDirect3DSurface9 *surface = nullptr;
493         ANGLE_TRY(getSurfaceLevel(context, index.getTarget(), mTopLevel + index.getLevelIndex(),
494                                   false, &surface));
495 
496         baseTexture->AddRef();
497         mRenderTarget[renderTargetIndex] = new TextureRenderTarget9(
498             baseTexture, mTopLevel + index.getLevelIndex(), surface, mInternalFormat,
499             static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0);
500     }
501 
502     *outRT = mRenderTarget[renderTargetIndex];
503     return angle::Result::Continue;
504 }
505 
generateMipmap(const gl::Context * context,const gl::ImageIndex & sourceIndex,const gl::ImageIndex & destIndex)506 angle::Result TextureStorage9_Cube::generateMipmap(const gl::Context *context,
507                                                    const gl::ImageIndex &sourceIndex,
508                                                    const gl::ImageIndex &destIndex)
509 {
510     angle::ComPtr<IDirect3DSurface9> upper = nullptr;
511     ANGLE_TRY(getSurfaceLevel(context, sourceIndex.getTarget(), sourceIndex.getLevelIndex(), false,
512                               &upper));
513 
514     angle::ComPtr<IDirect3DSurface9> lower = nullptr;
515     ANGLE_TRY(
516         getSurfaceLevel(context, destIndex.getTarget(), destIndex.getLevelIndex(), true, &lower));
517 
518     ASSERT(upper && lower);
519     return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get());
520 }
521 
getBaseTexture(const gl::Context * context,IDirect3DBaseTexture9 ** outTexture)522 angle::Result TextureStorage9_Cube::getBaseTexture(const gl::Context *context,
523                                                    IDirect3DBaseTexture9 **outTexture)
524 {
525     // if the size is not positive this should be treated as an incomplete texture
526     // we handle that here by skipping the d3d texture creation
527     if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0)
528     {
529         ASSERT(mMipLevels > 0);
530         ASSERT(mTextureWidth == mTextureHeight);
531 
532         IDirect3DDevice9 *device = mRenderer->getDevice();
533         HRESULT result           = device->CreateCubeTexture(
534             static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels),
535             getUsage(), mTextureFormat, getPool(), &mTexture, nullptr);
536         ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create cube storage texture");
537     }
538 
539     *outTexture = mTexture;
540     return angle::Result::Continue;
541 }
542 
copyToStorage(const gl::Context * context,TextureStorage * destStorage)543 angle::Result TextureStorage9_Cube::copyToStorage(const gl::Context *context,
544                                                   TextureStorage *destStorage)
545 {
546     ASSERT(destStorage);
547 
548     TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage);
549 
550     int levels = getLevelCount();
551     for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
552     {
553         for (int i = 0; i < levels; i++)
554         {
555             angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr;
556             ANGLE_TRY(getSurfaceLevel(context, face, i, false, &srcSurf));
557 
558             angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr;
559             ANGLE_TRY(dest9->getSurfaceLevel(context, face, i, true, &dstSurf));
560 
561             ANGLE_TRY(
562                 mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged()));
563         }
564     }
565 
566     return angle::Result::Continue;
567 }
568 }  // namespace rx
569