xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 // Context9:
7 //   D3D9-specific functionality associated with a GL Context.
8 //
9 
10 #include "libANGLE/renderer/d3d/d3d9/Context9.h"
11 
12 #include "common/entry_points_enum_autogen.h"
13 #include "common/string_utils.h"
14 #include "image_util/loadimage.h"
15 #include "libANGLE/renderer/OverlayImpl.h"
16 #include "libANGLE/renderer/d3d/CompilerD3D.h"
17 #include "libANGLE/renderer/d3d/ProgramD3D.h"
18 #include "libANGLE/renderer/d3d/ProgramExecutableD3D.h"
19 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
20 #include "libANGLE/renderer/d3d/SamplerD3D.h"
21 #include "libANGLE/renderer/d3d/ShaderD3D.h"
22 #include "libANGLE/renderer/d3d/TextureD3D.h"
23 #include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
24 #include "libANGLE/renderer/d3d/d3d9/Fence9.h"
25 #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
26 #include "libANGLE/renderer/d3d/d3d9/Query9.h"
27 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
28 #include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
29 #include "libANGLE/renderer/d3d/d3d9/VertexArray9.h"
30 
31 namespace rx
32 {
33 
Context9(const gl::State & state,gl::ErrorSet * errorSet,Renderer9 * renderer)34 Context9::Context9(const gl::State &state, gl::ErrorSet *errorSet, Renderer9 *renderer)
35     : ContextD3D(state, errorSet), mRenderer(renderer)
36 {}
37 
~Context9()38 Context9::~Context9() {}
39 
initialize(const angle::ImageLoadContext & imageLoadContext)40 angle::Result Context9::initialize(const angle::ImageLoadContext &imageLoadContext)
41 {
42     mImageLoadContext = imageLoadContext;
43     return angle::Result::Continue;
44 }
45 
onDestroy(const gl::Context * context)46 void Context9::onDestroy(const gl::Context *context)
47 {
48     mIncompleteTextures.onDestroy(context);
49 
50     mImageLoadContext = {};
51 }
52 
createCompiler()53 CompilerImpl *Context9::createCompiler()
54 {
55     return new CompilerD3D(SH_HLSL_3_0_OUTPUT);
56 }
57 
createShader(const gl::ShaderState & data)58 ShaderImpl *Context9::createShader(const gl::ShaderState &data)
59 {
60     return new ShaderD3D(data, mRenderer);
61 }
62 
createProgram(const gl::ProgramState & data)63 ProgramImpl *Context9::createProgram(const gl::ProgramState &data)
64 {
65     return new ProgramD3D(data, mRenderer);
66 }
67 
createProgramExecutable(const gl::ProgramExecutable * executable)68 ProgramExecutableImpl *Context9::createProgramExecutable(const gl::ProgramExecutable *executable)
69 {
70     return new ProgramExecutableD3D(executable);
71 }
72 
createFramebuffer(const gl::FramebufferState & data)73 FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data)
74 {
75     return new Framebuffer9(data, mRenderer);
76 }
77 
createTexture(const gl::TextureState & state)78 TextureImpl *Context9::createTexture(const gl::TextureState &state)
79 {
80     switch (state.getType())
81     {
82         case gl::TextureType::_2D:
83         // GL_TEXTURE_VIDEO_IMAGE_WEBGL maps to 2D texture on Windows platform.
84         case gl::TextureType::VideoImage:
85             return new TextureD3D_2D(state, mRenderer);
86         case gl::TextureType::CubeMap:
87             return new TextureD3D_Cube(state, mRenderer);
88         case gl::TextureType::External:
89             return new TextureD3D_External(state, mRenderer);
90         default:
91             UNREACHABLE();
92     }
93     return nullptr;
94 }
95 
createRenderbuffer(const gl::RenderbufferState & state)96 RenderbufferImpl *Context9::createRenderbuffer(const gl::RenderbufferState &state)
97 {
98     return new RenderbufferD3D(state, mRenderer);
99 }
100 
createBuffer(const gl::BufferState & state)101 BufferImpl *Context9::createBuffer(const gl::BufferState &state)
102 {
103     return new Buffer9(state, mRenderer);
104 }
105 
createVertexArray(const gl::VertexArrayState & data)106 VertexArrayImpl *Context9::createVertexArray(const gl::VertexArrayState &data)
107 {
108     return new VertexArray9(data);
109 }
110 
createQuery(gl::QueryType type)111 QueryImpl *Context9::createQuery(gl::QueryType type)
112 {
113     return new Query9(mRenderer, type);
114 }
115 
createFenceNV()116 FenceNVImpl *Context9::createFenceNV()
117 {
118     return new FenceNV9(mRenderer);
119 }
120 
createSync()121 SyncImpl *Context9::createSync()
122 {
123     // D3D9 doesn't support ES 3.0 and its sync objects.
124     UNREACHABLE();
125     return nullptr;
126 }
127 
createTransformFeedback(const gl::TransformFeedbackState & state)128 TransformFeedbackImpl *Context9::createTransformFeedback(const gl::TransformFeedbackState &state)
129 {
130     UNREACHABLE();
131     return nullptr;
132 }
133 
createSampler(const gl::SamplerState & state)134 SamplerImpl *Context9::createSampler(const gl::SamplerState &state)
135 {
136     return new SamplerD3D(state);
137 }
138 
createProgramPipeline(const gl::ProgramPipelineState & data)139 ProgramPipelineImpl *Context9::createProgramPipeline(const gl::ProgramPipelineState &data)
140 {
141     UNREACHABLE();
142     return nullptr;
143 }
144 
createMemoryObject()145 MemoryObjectImpl *Context9::createMemoryObject()
146 {
147     UNREACHABLE();
148     return nullptr;
149 }
150 
createSemaphore()151 SemaphoreImpl *Context9::createSemaphore()
152 {
153     UNREACHABLE();
154     return nullptr;
155 }
156 
createOverlay(const gl::OverlayState & state)157 OverlayImpl *Context9::createOverlay(const gl::OverlayState &state)
158 {
159     // Not implemented.
160     return new OverlayImpl(state);
161 }
162 
flush(const gl::Context * context)163 angle::Result Context9::flush(const gl::Context *context)
164 {
165     return mRenderer->flush(context);
166 }
167 
finish(const gl::Context * context)168 angle::Result Context9::finish(const gl::Context *context)
169 {
170     return mRenderer->finish(context);
171 }
172 
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)173 angle::Result Context9::drawArrays(const gl::Context *context,
174                                    gl::PrimitiveMode mode,
175                                    GLint first,
176                                    GLsizei count)
177 {
178     return mRenderer->genericDrawArrays(context, mode, first, count, 0);
179 }
180 
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instanceCount)181 angle::Result Context9::drawArraysInstanced(const gl::Context *context,
182                                             gl::PrimitiveMode mode,
183                                             GLint first,
184                                             GLsizei count,
185                                             GLsizei instanceCount)
186 {
187     return mRenderer->genericDrawArrays(context, mode, first, count, instanceCount);
188 }
189 
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instanceCount,GLuint baseInstance)190 angle::Result Context9::drawArraysInstancedBaseInstance(const gl::Context *context,
191                                                         gl::PrimitiveMode mode,
192                                                         GLint first,
193                                                         GLsizei count,
194                                                         GLsizei instanceCount,
195                                                         GLuint baseInstance)
196 {
197     ANGLE_HR_UNREACHABLE(this);
198     return angle::Result::Continue;
199 }
200 
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)201 angle::Result Context9::drawElements(const gl::Context *context,
202                                      gl::PrimitiveMode mode,
203                                      GLsizei count,
204                                      gl::DrawElementsType type,
205                                      const void *indices)
206 {
207     return mRenderer->genericDrawElements(context, mode, count, type, indices, 0);
208 }
209 
drawElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)210 angle::Result Context9::drawElementsBaseVertex(const gl::Context *context,
211                                                gl::PrimitiveMode mode,
212                                                GLsizei count,
213                                                gl::DrawElementsType type,
214                                                const void *indices,
215                                                GLint baseVertex)
216 {
217     ANGLE_HR_UNREACHABLE(this);
218     return angle::Result::Continue;
219 }
220 
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)221 angle::Result Context9::drawElementsInstanced(const gl::Context *context,
222                                               gl::PrimitiveMode mode,
223                                               GLsizei count,
224                                               gl::DrawElementsType type,
225                                               const void *indices,
226                                               GLsizei instances)
227 {
228     return mRenderer->genericDrawElements(context, mode, count, type, indices, instances);
229 }
230 
drawElementsInstancedBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex)231 angle::Result Context9::drawElementsInstancedBaseVertex(const gl::Context *context,
232                                                         gl::PrimitiveMode mode,
233                                                         GLsizei count,
234                                                         gl::DrawElementsType type,
235                                                         const void *indices,
236                                                         GLsizei instances,
237                                                         GLint baseVertex)
238 {
239     ANGLE_HR_UNREACHABLE(this);
240     return angle::Result::Continue;
241 }
242 
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)243 angle::Result Context9::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
244                                                                     gl::PrimitiveMode mode,
245                                                                     GLsizei count,
246                                                                     gl::DrawElementsType type,
247                                                                     const void *indices,
248                                                                     GLsizei instances,
249                                                                     GLint baseVertex,
250                                                                     GLuint baseInstance)
251 {
252     ANGLE_HR_UNREACHABLE(this);
253     return angle::Result::Continue;
254 }
255 
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)256 angle::Result Context9::drawRangeElements(const gl::Context *context,
257                                           gl::PrimitiveMode mode,
258                                           GLuint start,
259                                           GLuint end,
260                                           GLsizei count,
261                                           gl::DrawElementsType type,
262                                           const void *indices)
263 {
264     return mRenderer->genericDrawElements(context, mode, count, type, indices, 0);
265 }
266 
drawRangeElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)267 angle::Result Context9::drawRangeElementsBaseVertex(const gl::Context *context,
268                                                     gl::PrimitiveMode mode,
269                                                     GLuint start,
270                                                     GLuint end,
271                                                     GLsizei count,
272                                                     gl::DrawElementsType type,
273                                                     const void *indices,
274                                                     GLint baseVertex)
275 {
276     ANGLE_HR_UNREACHABLE(this);
277     return angle::Result::Continue;
278 }
279 
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)280 angle::Result Context9::drawArraysIndirect(const gl::Context *context,
281                                            gl::PrimitiveMode mode,
282                                            const void *indirect)
283 {
284     ANGLE_HR_UNREACHABLE(this);
285     return angle::Result::Stop;
286 }
287 
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)288 angle::Result Context9::drawElementsIndirect(const gl::Context *context,
289                                              gl::PrimitiveMode mode,
290                                              gl::DrawElementsType type,
291                                              const void *indirect)
292 {
293     ANGLE_HR_UNREACHABLE(this);
294     return angle::Result::Stop;
295 }
296 
multiDrawArrays(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)297 angle::Result Context9::multiDrawArrays(const gl::Context *context,
298                                         gl::PrimitiveMode mode,
299                                         const GLint *firsts,
300                                         const GLsizei *counts,
301                                         GLsizei drawcount)
302 {
303     return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
304 }
305 
multiDrawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,GLsizei drawcount)306 angle::Result Context9::multiDrawArraysInstanced(const gl::Context *context,
307                                                  gl::PrimitiveMode mode,
308                                                  const GLint *firsts,
309                                                  const GLsizei *counts,
310                                                  const GLsizei *instanceCounts,
311                                                  GLsizei drawcount)
312 {
313     return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
314                                                drawcount);
315 }
316 
multiDrawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)317 angle::Result Context9::multiDrawArraysIndirect(const gl::Context *context,
318                                                 gl::PrimitiveMode mode,
319                                                 const void *indirect,
320                                                 GLsizei drawcount,
321                                                 GLsizei stride)
322 {
323     UNREACHABLE();
324     return angle::Result::Stop;
325 }
326 
multiDrawElements(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,GLsizei drawcount)327 angle::Result Context9::multiDrawElements(const gl::Context *context,
328                                           gl::PrimitiveMode mode,
329                                           const GLsizei *counts,
330                                           gl::DrawElementsType type,
331                                           const GLvoid *const *indices,
332                                           GLsizei drawcount)
333 {
334     return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
335 }
336 
multiDrawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,GLsizei drawcount)337 angle::Result Context9::multiDrawElementsInstanced(const gl::Context *context,
338                                                    gl::PrimitiveMode mode,
339                                                    const GLsizei *counts,
340                                                    gl::DrawElementsType type,
341                                                    const GLvoid *const *indices,
342                                                    const GLsizei *instanceCounts,
343                                                    GLsizei drawcount)
344 {
345     return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
346                                                  instanceCounts, drawcount);
347 }
348 
multiDrawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)349 angle::Result Context9::multiDrawElementsIndirect(const gl::Context *context,
350                                                   gl::PrimitiveMode mode,
351                                                   gl::DrawElementsType type,
352                                                   const void *indirect,
353                                                   GLsizei drawcount,
354                                                   GLsizei stride)
355 {
356     UNREACHABLE();
357     return angle::Result::Stop;
358 }
359 
multiDrawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,const GLuint * baseInstances,GLsizei drawcount)360 angle::Result Context9::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
361                                                              gl::PrimitiveMode mode,
362                                                              const GLint *firsts,
363                                                              const GLsizei *counts,
364                                                              const GLsizei *instanceCounts,
365                                                              const GLuint *baseInstances,
366                                                              GLsizei drawcount)
367 {
368     ANGLE_HR_UNREACHABLE(this);
369     return angle::Result::Stop;
370 }
371 
multiDrawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,const GLint * baseVertices,const GLuint * baseInstances,GLsizei drawcount)372 angle::Result Context9::multiDrawElementsInstancedBaseVertexBaseInstance(
373     const gl::Context *context,
374     gl::PrimitiveMode mode,
375     const GLsizei *counts,
376     gl::DrawElementsType type,
377     const GLvoid *const *indices,
378     const GLsizei *instanceCounts,
379     const GLint *baseVertices,
380     const GLuint *baseInstances,
381     GLsizei drawcount)
382 {
383     ANGLE_HR_UNREACHABLE(this);
384     return angle::Result::Stop;
385 }
386 
getResetStatus()387 gl::GraphicsResetStatus Context9::getResetStatus()
388 {
389     return mRenderer->getResetStatus();
390 }
391 
insertEventMarker(GLsizei length,const char * marker)392 angle::Result Context9::insertEventMarker(GLsizei length, const char *marker)
393 {
394     mRenderer->getAnnotator()->setMarker(/*context=*/nullptr, marker);
395     return angle::Result::Continue;
396 }
397 
pushGroupMarker(GLsizei length,const char * marker)398 angle::Result Context9::pushGroupMarker(GLsizei length, const char *marker)
399 {
400     mRenderer->getAnnotator()->beginEvent(nullptr, angle::EntryPoint::GLPushGroupMarkerEXT, marker,
401                                           marker);
402     mMarkerStack.push(std::string(marker));
403     return angle::Result::Continue;
404 }
405 
popGroupMarker()406 angle::Result Context9::popGroupMarker()
407 {
408     const char *marker = nullptr;
409     if (!mMarkerStack.empty())
410     {
411         marker = mMarkerStack.top().c_str();
412         mMarkerStack.pop();
413         mRenderer->getAnnotator()->endEvent(nullptr, marker,
414                                             angle::EntryPoint::GLPopGroupMarkerEXT);
415     }
416     return angle::Result::Continue;
417 }
418 
pushDebugGroup(const gl::Context * context,GLenum source,GLuint id,const std::string & message)419 angle::Result Context9::pushDebugGroup(const gl::Context *context,
420                                        GLenum source,
421                                        GLuint id,
422                                        const std::string &message)
423 {
424     // Fall through to the EXT_debug_marker functions
425     return pushGroupMarker(static_cast<GLsizei>(message.size()), message.c_str());
426 }
427 
popDebugGroup(const gl::Context * context)428 angle::Result Context9::popDebugGroup(const gl::Context *context)
429 {
430     // Fall through to the EXT_debug_marker functions
431     return popGroupMarker();
432 }
433 
syncState(const gl::Context * context,const gl::state::DirtyBits dirtyBits,const gl::state::DirtyBits bitMask,const gl::state::ExtendedDirtyBits extendedDirtyBits,const gl::state::ExtendedDirtyBits extendedBitMask,gl::Command command)434 angle::Result Context9::syncState(const gl::Context *context,
435                                   const gl::state::DirtyBits dirtyBits,
436                                   const gl::state::DirtyBits bitMask,
437                                   const gl::state::ExtendedDirtyBits extendedDirtyBits,
438                                   const gl::state::ExtendedDirtyBits extendedBitMask,
439                                   gl::Command command)
440 {
441     mRenderer->getStateManager()->syncState(mState, dirtyBits, extendedDirtyBits);
442     return angle::Result::Continue;
443 }
444 
getGPUDisjoint()445 GLint Context9::getGPUDisjoint()
446 {
447     // Disjoint timer queries are not supported.
448     return false;
449 }
450 
getTimestamp()451 GLint64 Context9::getTimestamp()
452 {
453     return mRenderer->getTimestamp();
454 }
455 
onMakeCurrent(const gl::Context * context)456 angle::Result Context9::onMakeCurrent(const gl::Context *context)
457 {
458     mRenderer->getStateManager()->setAllDirtyBits();
459     return mRenderer->ensureVertexDataManagerInitialized(context);
460 }
461 
getNativeCaps() const462 gl::Caps Context9::getNativeCaps() const
463 {
464     return mRenderer->getNativeCaps();
465 }
466 
getNativeTextureCaps() const467 const gl::TextureCapsMap &Context9::getNativeTextureCaps() const
468 {
469     return mRenderer->getNativeTextureCaps();
470 }
471 
getNativeExtensions() const472 const gl::Extensions &Context9::getNativeExtensions() const
473 {
474     return mRenderer->getNativeExtensions();
475 }
476 
getNativeLimitations() const477 const gl::Limitations &Context9::getNativeLimitations() const
478 {
479     return mRenderer->getNativeLimitations();
480 }
481 
getNativePixelLocalStorageOptions() const482 const ShPixelLocalStorageOptions &Context9::getNativePixelLocalStorageOptions() const
483 {
484     return mRenderer->getNativePixelLocalStorageOptions();
485 }
486 
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)487 angle::Result Context9::dispatchCompute(const gl::Context *context,
488                                         GLuint numGroupsX,
489                                         GLuint numGroupsY,
490                                         GLuint numGroupsZ)
491 {
492     ANGLE_HR_UNREACHABLE(this);
493     return angle::Result::Stop;
494 }
495 
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)496 angle::Result Context9::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
497 {
498     ANGLE_HR_UNREACHABLE(this);
499     return angle::Result::Stop;
500 }
501 
memoryBarrier(const gl::Context * context,GLbitfield barriers)502 angle::Result Context9::memoryBarrier(const gl::Context *context, GLbitfield barriers)
503 {
504     ANGLE_HR_UNREACHABLE(this);
505     return angle::Result::Stop;
506 }
507 
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)508 angle::Result Context9::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
509 {
510     ANGLE_HR_UNREACHABLE(this);
511     return angle::Result::Stop;
512 }
513 
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::Texture ** textureOut)514 angle::Result Context9::getIncompleteTexture(const gl::Context *context,
515                                              gl::TextureType type,
516                                              gl::Texture **textureOut)
517 {
518     return mIncompleteTextures.getIncompleteTexture(context, type, gl::SamplerFormat::Float,
519                                                     nullptr, textureOut);
520 }
521 
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)522 void Context9::handleResult(HRESULT hr,
523                             const char *message,
524                             const char *file,
525                             const char *function,
526                             unsigned int line)
527 {
528     ASSERT(FAILED(hr));
529 
530     if (d3d9::isDeviceLostError(hr))
531     {
532         mRenderer->notifyDeviceLost();
533     }
534 
535     GLenum glErrorCode = DefaultGLErrorCode(hr);
536 
537     std::stringstream errorStream;
538     errorStream << "Internal D3D9 error: " << gl::FmtHR(hr) << ": " << message;
539 
540     mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
541 }
542 }  // namespace rx
543