color_space_win.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // Copyright (c) 2012 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 "ui/gfx/color_space_win.h"
  5. #include "base/logging.h"
  6. #include "third_party/skia/modules/skcms/skcms.h"
  7. namespace gfx {
  8. DXVA2_ExtendedFormat ColorSpaceWin::GetExtendedFormat(
  9. const ColorSpace& color_space) {
  10. DXVA2_ExtendedFormat format;
  11. memset(&format, 0, sizeof(format));
  12. format.SampleFormat = DXVA2_SampleProgressiveFrame;
  13. format.VideoLighting = DXVA2_VideoLighting_dim;
  14. format.NominalRange = DXVA2_NominalRange_16_235;
  15. format.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT709;
  16. format.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
  17. format.VideoTransferFunction = DXVA2_VideoTransFunc_709;
  18. switch (color_space.GetRangeID()) {
  19. case gfx::ColorSpace::RangeID::LIMITED:
  20. format.NominalRange = DXVA2_NominalRange_16_235;
  21. break;
  22. case gfx::ColorSpace::RangeID::FULL:
  23. format.NominalRange = DXVA2_NominalRange_0_255;
  24. break;
  25. case gfx::ColorSpace::RangeID::DERIVED:
  26. case gfx::ColorSpace::RangeID::INVALID:
  27. // Not handled
  28. break;
  29. }
  30. switch (color_space.GetMatrixID()) {
  31. case gfx::ColorSpace::MatrixID::BT709:
  32. format.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT709;
  33. break;
  34. case gfx::ColorSpace::MatrixID::BT470BG:
  35. case gfx::ColorSpace::MatrixID::SMPTE170M:
  36. format.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT601;
  37. break;
  38. case gfx::ColorSpace::MatrixID::SMPTE240M:
  39. format.VideoTransferMatrix = DXVA2_VideoTransferMatrix_SMPTE240M;
  40. break;
  41. case gfx::ColorSpace::MatrixID::RGB:
  42. case gfx::ColorSpace::MatrixID::GBR:
  43. case gfx::ColorSpace::MatrixID::FCC:
  44. case gfx::ColorSpace::MatrixID::YCOCG:
  45. case gfx::ColorSpace::MatrixID::BT2020_NCL:
  46. case gfx::ColorSpace::MatrixID::BT2020_CL:
  47. case gfx::ColorSpace::MatrixID::YDZDX:
  48. case gfx::ColorSpace::MatrixID::INVALID:
  49. // Not handled
  50. break;
  51. }
  52. switch (color_space.GetPrimaryID()) {
  53. case gfx::ColorSpace::PrimaryID::BT709:
  54. format.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
  55. break;
  56. case gfx::ColorSpace::PrimaryID::BT470M:
  57. format.VideoPrimaries = DXVA2_VideoPrimaries_BT470_2_SysM;
  58. break;
  59. case gfx::ColorSpace::PrimaryID::BT470BG:
  60. format.VideoPrimaries = DXVA2_VideoPrimaries_BT470_2_SysBG;
  61. break;
  62. case gfx::ColorSpace::PrimaryID::SMPTE170M:
  63. format.VideoPrimaries = DXVA2_VideoPrimaries_SMPTE170M;
  64. break;
  65. case gfx::ColorSpace::PrimaryID::SMPTE240M:
  66. format.VideoPrimaries = DXVA2_VideoPrimaries_SMPTE240M;
  67. break;
  68. case gfx::ColorSpace::PrimaryID::FILM:
  69. case gfx::ColorSpace::PrimaryID::BT2020:
  70. case gfx::ColorSpace::PrimaryID::SMPTEST428_1:
  71. case gfx::ColorSpace::PrimaryID::SMPTEST431_2:
  72. case gfx::ColorSpace::PrimaryID::P3:
  73. case gfx::ColorSpace::PrimaryID::XYZ_D50:
  74. case gfx::ColorSpace::PrimaryID::ADOBE_RGB:
  75. case gfx::ColorSpace::PrimaryID::APPLE_GENERIC_RGB:
  76. case gfx::ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN:
  77. case gfx::ColorSpace::PrimaryID::CUSTOM:
  78. case gfx::ColorSpace::PrimaryID::INVALID:
  79. // Not handled
  80. break;
  81. }
  82. switch (color_space.GetTransferID()) {
  83. case gfx::ColorSpace::TransferID::BT709:
  84. case gfx::ColorSpace::TransferID::SMPTE170M:
  85. format.VideoTransferFunction = DXVA2_VideoTransFunc_709;
  86. break;
  87. case gfx::ColorSpace::TransferID::SMPTE240M:
  88. format.VideoTransferFunction = DXVA2_VideoTransFunc_240M;
  89. break;
  90. case gfx::ColorSpace::TransferID::GAMMA22:
  91. format.VideoTransferFunction = DXVA2_VideoTransFunc_22;
  92. break;
  93. case gfx::ColorSpace::TransferID::GAMMA28:
  94. format.VideoTransferFunction = DXVA2_VideoTransFunc_28;
  95. break;
  96. case gfx::ColorSpace::TransferID::LINEAR:
  97. case gfx::ColorSpace::TransferID::LINEAR_HDR:
  98. case gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS:
  99. format.VideoTransferFunction = DXVA2_VideoTransFunc_10;
  100. break;
  101. case gfx::ColorSpace::TransferID::SRGB:
  102. case gfx::ColorSpace::TransferID::SRGB_HDR:
  103. format.VideoTransferFunction = DXVA2_VideoTransFunc_sRGB;
  104. break;
  105. case gfx::ColorSpace::TransferID::LOG:
  106. case gfx::ColorSpace::TransferID::LOG_SQRT:
  107. case gfx::ColorSpace::TransferID::IEC61966_2_4:
  108. case gfx::ColorSpace::TransferID::BT1361_ECG:
  109. case gfx::ColorSpace::TransferID::BT2020_10:
  110. case gfx::ColorSpace::TransferID::BT2020_12:
  111. case gfx::ColorSpace::TransferID::PQ:
  112. case gfx::ColorSpace::TransferID::SMPTEST428_1:
  113. case gfx::ColorSpace::TransferID::HLG:
  114. case gfx::ColorSpace::TransferID::BT709_APPLE:
  115. case gfx::ColorSpace::TransferID::GAMMA18:
  116. case gfx::ColorSpace::TransferID::GAMMA24:
  117. case gfx::ColorSpace::TransferID::CUSTOM:
  118. case gfx::ColorSpace::TransferID::CUSTOM_HDR:
  119. case gfx::ColorSpace::TransferID::PIECEWISE_HDR:
  120. case gfx::ColorSpace::TransferID::INVALID:
  121. // Not handled
  122. break;
  123. }
  124. return format;
  125. }
  126. DXGI_COLOR_SPACE_TYPE ColorSpaceWin::GetDXGIColorSpace(
  127. const ColorSpace& color_space,
  128. bool force_yuv) {
  129. // Treat invalid color space as sRGB.
  130. if (!color_space.IsValid())
  131. return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
  132. if (color_space.GetMatrixID() == gfx::ColorSpace::MatrixID::RGB &&
  133. !force_yuv) {
  134. // For RGB, we default to FULL
  135. if (color_space.GetRangeID() == gfx::ColorSpace::RangeID::LIMITED) {
  136. if (color_space.GetPrimaryID() == gfx::ColorSpace::PrimaryID::BT2020) {
  137. if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ) {
  138. return DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020;
  139. } else {
  140. return DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020;
  141. }
  142. } else {
  143. return DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709;
  144. }
  145. } else {
  146. if (color_space.GetPrimaryID() == gfx::ColorSpace::PrimaryID::BT2020) {
  147. if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ) {
  148. return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
  149. } else {
  150. return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020;
  151. }
  152. } else {
  153. if (color_space.GetTransferID() ==
  154. gfx::ColorSpace::TransferID::LINEAR ||
  155. color_space.GetTransferID() ==
  156. gfx::ColorSpace::TransferID::LINEAR_HDR ||
  157. color_space.GetTransferID() ==
  158. gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS) {
  159. return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
  160. } else if (color_space.GetTransferID() ==
  161. gfx::ColorSpace::TransferID::CUSTOM_HDR) {
  162. skcms_TransferFunction fn;
  163. color_space.GetTransferFunction(&fn);
  164. if (fn.g == 1.f)
  165. return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
  166. else
  167. DLOG(ERROR) << "Windows HDR only supports gamma=1.0.";
  168. }
  169. return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
  170. }
  171. }
  172. } else {
  173. if (color_space.GetPrimaryID() == gfx::ColorSpace::PrimaryID::BT2020) {
  174. if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ) {
  175. return DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;
  176. // Could also be:
  177. // DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
  178. } else if (color_space.GetTransferID() ==
  179. gfx::ColorSpace::TransferID::HLG) {
  180. // Note: This may not always work. See https://crbug.com/1144260#c6.
  181. return DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;
  182. } else {
  183. // For YUV, we default to LIMITED
  184. if (color_space.GetRangeID() == gfx::ColorSpace::RangeID::FULL) {
  185. return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020;
  186. } else {
  187. return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020;
  188. // Could also be:
  189. // DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020
  190. }
  191. }
  192. } else if (color_space.GetPrimaryID() ==
  193. gfx::ColorSpace::PrimaryID::BT470BG ||
  194. color_space.GetPrimaryID() ==
  195. gfx::ColorSpace::PrimaryID::SMPTE170M) {
  196. // For YUV, we default to LIMITED
  197. if (color_space.GetRangeID() == gfx::ColorSpace::RangeID::FULL) {
  198. return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601;
  199. } else {
  200. return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601;
  201. }
  202. } else {
  203. // For YUV, we default to LIMITED
  204. if (color_space.GetRangeID() == gfx::ColorSpace::RangeID::FULL) {
  205. // TODO(hubbe): Check if this is correct.
  206. if (color_space.GetTransferID() ==
  207. gfx::ColorSpace::TransferID::SMPTE170M) {
  208. return DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601;
  209. } else {
  210. return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709;
  211. }
  212. } else {
  213. return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
  214. }
  215. }
  216. }
  217. }
  218. DXGI_FORMAT ColorSpaceWin::GetDXGIFormat(const gfx::ColorSpace& color_space) {
  219. // The PQ transfer function needs 10 bits.
  220. if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ)
  221. return DXGI_FORMAT_R10G10B10A2_UNORM;
  222. // Non-PQ HDR color spaces use half-float.
  223. if (color_space.IsHDR())
  224. return DXGI_FORMAT_R16G16B16A16_FLOAT;
  225. // For now just give everything else 8 bits. We will want to use 10 or 16 bits
  226. // for BT2020 gamuts.
  227. return DXGI_FORMAT_B8G8R8A8_UNORM;
  228. }
  229. D3D11_VIDEO_PROCESSOR_COLOR_SPACE ColorSpaceWin::GetD3D11ColorSpace(
  230. const ColorSpace& color_space) {
  231. D3D11_VIDEO_PROCESSOR_COLOR_SPACE ret = {0};
  232. if (color_space.GetRangeID() == gfx::ColorSpace::RangeID::FULL) {
  233. ret.RGB_Range = 0; // FULL
  234. ret.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255;
  235. } else {
  236. ret.RGB_Range = 1; // LIMITED
  237. ret.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
  238. }
  239. switch (color_space.GetMatrixID()) {
  240. case gfx::ColorSpace::MatrixID::BT709:
  241. ret.YCbCr_Matrix = 1;
  242. break;
  243. case gfx::ColorSpace::MatrixID::BT470BG:
  244. case gfx::ColorSpace::MatrixID::SMPTE170M:
  245. ret.YCbCr_Matrix = 0;
  246. break;
  247. case gfx::ColorSpace::MatrixID::SMPTE240M:
  248. case gfx::ColorSpace::MatrixID::RGB:
  249. case gfx::ColorSpace::MatrixID::GBR:
  250. case gfx::ColorSpace::MatrixID::FCC:
  251. case gfx::ColorSpace::MatrixID::YCOCG:
  252. case gfx::ColorSpace::MatrixID::BT2020_NCL:
  253. case gfx::ColorSpace::MatrixID::BT2020_CL:
  254. case gfx::ColorSpace::MatrixID::YDZDX:
  255. case gfx::ColorSpace::MatrixID::INVALID:
  256. // Not handled
  257. break;
  258. }
  259. return ret;
  260. }
  261. } // namespace gfx