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