shared_image_video_frame_test_utils.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/renderers/shared_image_video_frame_test_utils.h"
  5. #include "base/logging.h"
  6. #include "components/viz/common/gpu/context_provider.h"
  7. #include "gpu/GLES2/gl2extchromium.h"
  8. #include "gpu/command_buffer/client/gles2_interface_stub.h"
  9. #include "gpu/command_buffer/client/shared_image_interface.h"
  10. #include "gpu/command_buffer/common/capabilities.h"
  11. #include "gpu/command_buffer/common/shared_image_usage.h"
  12. namespace media {
  13. namespace {
  14. static constexpr const uint8_t kYuvColors[8][3] = {
  15. {0x00, 0x80, 0x80}, // Black
  16. {0x4c, 0x54, 0xff}, // Red
  17. {0x95, 0x2b, 0x15}, // Green
  18. {0xe1, 0x00, 0x94}, // Yellow
  19. {0x1d, 0xff, 0x6b}, // Blue
  20. {0x69, 0xd3, 0xec}, // Magenta
  21. {0xb3, 0xaa, 0x00}, // Cyan
  22. {0xff, 0x80, 0x80}, // White
  23. };
  24. // Destroys a list of shared images after a sync token is passed. Also runs
  25. // |callback|.
  26. void DestroySharedImages(scoped_refptr<viz::ContextProvider> context_provider,
  27. std::vector<gpu::Mailbox> mailboxes,
  28. base::OnceClosure callback,
  29. const gpu::SyncToken& sync_token) {
  30. auto* sii = context_provider->SharedImageInterface();
  31. for (const auto& mailbox : mailboxes)
  32. sii->DestroySharedImage(sync_token, mailbox);
  33. std::move(callback).Run();
  34. }
  35. // Upload pixels to a shared image using GL.
  36. void UploadPixels(gpu::gles2::GLES2Interface* gl,
  37. const gpu::Mailbox& mailbox,
  38. const gfx::Size& size,
  39. GLenum format,
  40. GLenum type,
  41. const uint8_t* data) {
  42. GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
  43. gl->BeginSharedImageAccessDirectCHROMIUM(
  44. texture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
  45. gl->BindTexture(GL_TEXTURE_2D, texture);
  46. gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), format,
  47. type, data);
  48. gl->EndSharedImageAccessDirectCHROMIUM(texture);
  49. gl->DeleteTextures(1, &texture);
  50. }
  51. } // namespace
  52. scoped_refptr<VideoFrame> CreateSharedImageFrame(
  53. scoped_refptr<viz::ContextProvider> context_provider,
  54. VideoPixelFormat format,
  55. std::vector<gpu::Mailbox> mailboxes,
  56. const gpu::SyncToken& sync_token,
  57. GLenum texture_target,
  58. const gfx::Size& coded_size,
  59. const gfx::Rect& visible_rect,
  60. const gfx::Size& natural_size,
  61. base::TimeDelta timestamp,
  62. base::OnceClosure destroyed_callback) {
  63. gpu::MailboxHolder mailboxes_for_frame[VideoFrame::kMaxPlanes] = {};
  64. size_t i = 0;
  65. for (const auto& mailbox : mailboxes) {
  66. mailboxes_for_frame[i++] =
  67. gpu::MailboxHolder(mailbox, sync_token, texture_target);
  68. }
  69. auto callback =
  70. base::BindOnce(&DestroySharedImages, std::move(context_provider),
  71. std::move(mailboxes), std::move(destroyed_callback));
  72. return VideoFrame::WrapNativeTextures(format, mailboxes_for_frame,
  73. std::move(callback), coded_size,
  74. visible_rect, natural_size, timestamp);
  75. }
  76. scoped_refptr<VideoFrame> CreateSharedImageRGBAFrame(
  77. scoped_refptr<viz::ContextProvider> context_provider,
  78. const gfx::Size& coded_size,
  79. const gfx::Rect& visible_rect,
  80. base::OnceClosure destroyed_callback) {
  81. DCHECK_EQ(coded_size.width() % 4, 0);
  82. DCHECK_EQ(coded_size.height() % 2, 0);
  83. size_t pixels_size = coded_size.GetArea() * 4;
  84. auto pixels = std::make_unique<uint8_t[]>(pixels_size);
  85. size_t i = 0;
  86. for (size_t block_y = 0; block_y < 2u; ++block_y) {
  87. for (int y = 0; y < coded_size.height() / 2; ++y) {
  88. for (size_t block_x = 0; block_x < 4u; ++block_x) {
  89. for (int x = 0; x < coded_size.width() / 4; ++x) {
  90. pixels[i++] = 0xffu * (block_x % 2); // R
  91. pixels[i++] = 0xffu * (block_x / 2); // G
  92. pixels[i++] = 0xffu * block_y; // B
  93. pixels[i++] = 0xffu; // A
  94. }
  95. }
  96. }
  97. }
  98. DCHECK_EQ(i, pixels_size);
  99. auto* sii = context_provider->SharedImageInterface();
  100. gpu::Mailbox mailbox = sii->CreateSharedImage(
  101. viz::ResourceFormat::RGBA_8888, coded_size, gfx::ColorSpace(),
  102. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
  103. gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
  104. auto* gl = context_provider->ContextGL();
  105. gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
  106. UploadPixels(gl, mailbox, coded_size, GL_RGBA, GL_UNSIGNED_BYTE,
  107. pixels.get());
  108. gpu::SyncToken sync_token;
  109. gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
  110. return CreateSharedImageFrame(
  111. std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_ABGR,
  112. {mailbox}, sync_token, GL_TEXTURE_2D, coded_size, visible_rect,
  113. visible_rect.size(), base::Seconds(1), std::move(destroyed_callback));
  114. }
  115. scoped_refptr<VideoFrame> CreateSharedImageI420Frame(
  116. scoped_refptr<viz::ContextProvider> context_provider,
  117. const gfx::Size& coded_size,
  118. const gfx::Rect& visible_rect,
  119. base::OnceClosure destroyed_callback) {
  120. DCHECK_EQ(coded_size.width() % 8, 0);
  121. DCHECK_EQ(coded_size.height() % 4, 0);
  122. gfx::Size uv_size(coded_size.width() / 2, coded_size.height() / 2);
  123. size_t y_pixels_size = coded_size.GetArea();
  124. size_t uv_pixels_size = uv_size.GetArea();
  125. auto y_pixels = std::make_unique<uint8_t[]>(y_pixels_size);
  126. auto u_pixels = std::make_unique<uint8_t[]>(uv_pixels_size);
  127. auto v_pixels = std::make_unique<uint8_t[]>(uv_pixels_size);
  128. size_t y_i = 0;
  129. size_t uv_i = 0;
  130. for (size_t block_y = 0; block_y < 2u; ++block_y) {
  131. for (int y = 0; y < coded_size.height() / 2; ++y) {
  132. for (size_t block_x = 0; block_x < 4u; ++block_x) {
  133. size_t color_index = block_x + block_y * 4;
  134. const uint8_t* yuv = kYuvColors[color_index];
  135. for (int x = 0; x < coded_size.width() / 4; ++x) {
  136. y_pixels[y_i++] = yuv[0];
  137. if ((x % 2) && (y % 2)) {
  138. u_pixels[uv_i] = yuv[1];
  139. v_pixels[uv_i++] = yuv[2];
  140. }
  141. }
  142. }
  143. }
  144. }
  145. DCHECK_EQ(y_i, y_pixels_size);
  146. DCHECK_EQ(uv_i, uv_pixels_size);
  147. auto* sii = context_provider->SharedImageInterface();
  148. gpu::Mailbox y_mailbox = sii->CreateSharedImage(
  149. viz::ResourceFormat::LUMINANCE_8, coded_size, gfx::ColorSpace(),
  150. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
  151. gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
  152. gpu::Mailbox u_mailbox = sii->CreateSharedImage(
  153. viz::ResourceFormat::LUMINANCE_8, uv_size, gfx::ColorSpace(),
  154. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
  155. gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
  156. gpu::Mailbox v_mailbox = sii->CreateSharedImage(
  157. viz::ResourceFormat::LUMINANCE_8, uv_size, gfx::ColorSpace(),
  158. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
  159. gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
  160. auto* gl = context_provider->ContextGL();
  161. gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
  162. UploadPixels(gl, y_mailbox, coded_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  163. y_pixels.get());
  164. UploadPixels(gl, u_mailbox, uv_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  165. u_pixels.get());
  166. UploadPixels(gl, v_mailbox, uv_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  167. v_pixels.get());
  168. gpu::SyncToken sync_token;
  169. gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
  170. return CreateSharedImageFrame(
  171. std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_I420,
  172. {y_mailbox, u_mailbox, v_mailbox}, sync_token, GL_TEXTURE_2D, coded_size,
  173. visible_rect, visible_rect.size(), base::Seconds(1),
  174. std::move(destroyed_callback));
  175. }
  176. scoped_refptr<VideoFrame> CreateSharedImageNV12Frame(
  177. scoped_refptr<viz::ContextProvider> context_provider,
  178. const gfx::Size& coded_size,
  179. const gfx::Rect& visible_rect,
  180. base::OnceClosure destroyed_callback) {
  181. DCHECK_EQ(coded_size.width() % 8, 0);
  182. DCHECK_EQ(coded_size.height() % 4, 0);
  183. if (!context_provider->ContextCapabilities().texture_rg) {
  184. LOG(ERROR) << "GL_EXT_texture_rg not supported";
  185. return {};
  186. }
  187. gfx::Size uv_size(coded_size.width() / 2, coded_size.height() / 2);
  188. size_t y_pixels_size = coded_size.GetArea();
  189. size_t uv_pixels_size = uv_size.GetArea() * 2;
  190. auto y_pixels = std::make_unique<uint8_t[]>(y_pixels_size);
  191. auto uv_pixels = std::make_unique<uint8_t[]>(uv_pixels_size);
  192. size_t y_i = 0;
  193. size_t uv_i = 0;
  194. for (size_t block_y = 0; block_y < 2u; ++block_y) {
  195. for (int y = 0; y < coded_size.height() / 2; ++y) {
  196. for (size_t block_x = 0; block_x < 4u; ++block_x) {
  197. size_t color_index = block_x + block_y * 4;
  198. const uint8_t* yuv = kYuvColors[color_index];
  199. for (int x = 0; x < coded_size.width() / 4; ++x) {
  200. y_pixels[y_i++] = yuv[0];
  201. if ((x % 2) && (y % 2)) {
  202. uv_pixels[uv_i++] = yuv[1];
  203. uv_pixels[uv_i++] = yuv[2];
  204. }
  205. }
  206. }
  207. }
  208. }
  209. DCHECK_EQ(y_i, y_pixels_size);
  210. DCHECK_EQ(uv_i, uv_pixels_size);
  211. auto* sii = context_provider->SharedImageInterface();
  212. gpu::Mailbox y_mailbox = sii->CreateSharedImage(
  213. viz::ResourceFormat::LUMINANCE_8, coded_size, gfx::ColorSpace(),
  214. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
  215. gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
  216. gpu::Mailbox uv_mailbox = sii->CreateSharedImage(
  217. viz::ResourceFormat::RG_88, uv_size, gfx::ColorSpace(),
  218. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
  219. gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
  220. auto* gl = context_provider->ContextGL();
  221. gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
  222. UploadPixels(gl, y_mailbox, coded_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  223. y_pixels.get());
  224. UploadPixels(gl, uv_mailbox, uv_size, GL_RG, GL_UNSIGNED_BYTE,
  225. uv_pixels.get());
  226. gpu::SyncToken sync_token;
  227. gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
  228. return CreateSharedImageFrame(
  229. std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_NV12,
  230. {y_mailbox, uv_mailbox}, sync_token, GL_TEXTURE_2D, coded_size,
  231. visible_rect, visible_rect.size(), base::Seconds(1),
  232. std::move(destroyed_callback));
  233. }
  234. } // namespace media