OpenGLGraphicsDevice.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #include "pch.h"
  2. #include "third_party/libyuv/include/libyuv.h"
  3. #include "OpenGLGraphicsDevice.h"
  4. #include "OpenGLTexture2D.h"
  5. #include "GraphicsDevice/GraphicsUtility.h"
  6. #include "OpenGLContext.h"
  7. #if CUDA_PLATFORM
  8. #include <cuda.h>
  9. #include <cudaGL.h>
  10. #include "GraphicsDevice/Cuda/GpuMemoryBufferCudaHandle.h"
  11. #else
  12. #include "GpuMemoryBuffer.h"
  13. #endif
  14. namespace unity
  15. {
  16. namespace webrtc
  17. {
  18. #if SUPPORT_OPENGL_ES
  19. GLuint fbo[2];
  20. #endif
  21. Size glTexSize(GLenum target, GLuint texture, GLint mipLevel)
  22. {
  23. int width = 0, height = 0;
  24. glBindTexture(target, texture);
  25. glGetTexLevelParameteriv(target, mipLevel, GL_TEXTURE_WIDTH, &width);
  26. glGetTexLevelParameteriv(target, mipLevel, GL_TEXTURE_HEIGHT, &height);
  27. glBindTexture(target, 0);
  28. return Size(width, height);
  29. }
  30. OpenGLGraphicsDevice::OpenGLGraphicsDevice(
  31. UnityGfxRenderer renderer, ProfilerMarkerFactory* profiler)
  32. : IGraphicsDevice(renderer, profiler)
  33. , mainContext_(nullptr)
  34. {
  35. OpenGLContext::Init();
  36. mainContext_ = OpenGLContext::CurrentContext();
  37. RTC_DCHECK(mainContext_);
  38. }
  39. //---------------------------------------------------------------------------------------------------------------------
  40. OpenGLGraphicsDevice::~OpenGLGraphicsDevice()
  41. {
  42. }
  43. //---------------------------------------------------------------------------------------------------------------------
  44. bool OpenGLGraphicsDevice::InitV()
  45. {
  46. #if _DEBUG
  47. GLuint unusedIds = 0;
  48. glEnable(GL_DEBUG_OUTPUT);
  49. glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
  50. #if SUPPORT_OPENGL_CORE
  51. glDebugMessageCallback(OnOpenGLDebugMessage, nullptr);
  52. glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unusedIds, true);
  53. #endif
  54. #endif
  55. #if SUPPORT_OPENGL_ES
  56. glGenFramebuffers(2, fbo);
  57. #endif
  58. #if CUDA_PLATFORM
  59. m_isCudaSupport = CUDA_SUCCESS == m_cudaContext.InitGL();
  60. #endif
  61. return true;
  62. }
  63. //---------------------------------------------------------------------------------------------------------------------
  64. void OpenGLGraphicsDevice::ShutdownV() {
  65. #if SUPPORT_OPENGL_ES
  66. glDeleteFramebuffers(2, fbo);
  67. #endif
  68. #if CUDA_PLATFORM
  69. m_cudaContext.Shutdown();
  70. #endif
  71. }
  72. //---------------------------------------------------------------------------------------------------------------------
  73. ITexture2D* OpenGLGraphicsDevice::CreateDefaultTextureV(
  74. uint32_t w, uint32_t h, UnityRenderingExtTextureFormat textureFormat)
  75. {
  76. GLuint tex;
  77. glGenTextures(1, &tex);
  78. glBindTexture(GL_TEXTURE_2D, tex);
  79. glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, w, h);
  80. glBindTexture(GL_TEXTURE_2D, 0);
  81. OpenGLTexture2D::ReleaseOpenGLTextureCallback callback =
  82. std::bind(&OpenGLGraphicsDevice::ReleaseTexture, this, std::placeholders::_1);
  83. return new OpenGLTexture2D(w, h, tex, callback);
  84. }
  85. //---------------------------------------------------------------------------------------------------------------------
  86. ITexture2D* OpenGLGraphicsDevice::CreateCPUReadTextureV(
  87. uint32_t w, uint32_t h, UnityRenderingExtTextureFormat textureFormat)
  88. {
  89. OpenGLTexture2D* tex = static_cast<OpenGLTexture2D*>(CreateDefaultTextureV(w, h, textureFormat));
  90. tex->CreatePBO();
  91. return tex;
  92. }
  93. //---------------------------------------------------------------------------------------------------------------------
  94. bool OpenGLGraphicsDevice::CopyResourceV(ITexture2D* dst, ITexture2D* src)
  95. {
  96. OpenGLTexture2D* srcTexture = static_cast<OpenGLTexture2D*>(src);
  97. OpenGLTexture2D* dstTexture = static_cast<OpenGLTexture2D*>(dst);
  98. const GLuint srcName = srcTexture->GetTexture();
  99. const GLuint dstName = dstTexture->GetTexture();
  100. return CopyResource(dstName, srcName);
  101. }
  102. //---------------------------------------------------------------------------------------------------------------------
  103. bool OpenGLGraphicsDevice::CopyResourceFromNativeV(ITexture2D* dst, void* nativeTexturePtr)
  104. {
  105. OpenGLTexture2D* dstTexture = static_cast<OpenGLTexture2D*>(dst);
  106. const GLuint srcName = reinterpret_cast<uintptr_t>(nativeTexturePtr);
  107. const GLuint dstName = dstTexture->GetTexture();
  108. return CopyResource(dstName, srcName);
  109. }
  110. bool OpenGLGraphicsDevice::CopyResource(GLuint dstName, GLuint srcName)
  111. {
  112. if(srcName == dstName)
  113. {
  114. RTC_LOG(LS_INFO) << "Same texture";
  115. return false;
  116. }
  117. if(glIsTexture(srcName) == GL_FALSE)
  118. {
  119. RTC_LOG(LS_INFO) << "srcName is not texture";
  120. return false;
  121. }
  122. if(glIsTexture(dstName) == GL_FALSE)
  123. {
  124. RTC_LOG(LS_INFO) << "dstName is not texture";
  125. return false;
  126. }
  127. Size srcSize = glTexSize(GL_TEXTURE_2D, srcName, 0);
  128. Size dstSize = glTexSize(GL_TEXTURE_2D, dstName, 0);
  129. if(srcSize.width() == 0 || srcSize.height() == 0)
  130. {
  131. RTC_LOG(LS_INFO) << "texture size is not valid";
  132. return false;
  133. }
  134. if(srcSize != dstSize)
  135. {
  136. RTC_LOG(LS_INFO) << "texture size is not same";
  137. return false;
  138. }
  139. // todo(kazuki): "glCopyImageSubData" is available since OpenGL ES 3.2 on Android platform.
  140. // OpenGL ES 3.2 is needed to use API level 24.
  141. glCopyImageSubData(
  142. srcName, GL_TEXTURE_2D, 0, 0, 0, 0,
  143. dstName, GL_TEXTURE_2D, 0, 0, 0, 0,
  144. dstSize.width(), dstSize.height(), 1);
  145. // todo(kazuki): "glFinish" is used to sync GPU for waiting to copy the texture buffer.
  146. // But this command affects graphics performance.
  147. glFinish();
  148. return true;
  149. }
  150. void OpenGLGraphicsDevice::ReleaseTexture(OpenGLTexture2D* texture)
  151. {
  152. if(!OpenGLContext::CurrentContext())
  153. contexts_.push_back(OpenGLContext::CreateGLContext(mainContext_.get()));
  154. texture->Release();
  155. }
  156. void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels)
  157. {
  158. #if SUPPORT_OPENGL_CORE
  159. glGetTexImage(target, level, format, type, pixels);
  160. #elif SUPPORT_OPENGL_ES
  161. glBindFramebuffer( GL_FRAMEBUFFER, fbo[0] );
  162. int width = 0;
  163. int height = 0;
  164. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
  165. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
  166. GLint tex;
  167. glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
  168. glFramebufferTexture2D(GL_FRAMEBUFFER,
  169. GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
  170. // read pixels from framebuffer to PBO
  171. glReadBuffer(GL_COLOR_ATTACHMENT0);
  172. glReadPixels(0, 0, width, height, format, type, pixels);
  173. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  174. #endif
  175. }
  176. rtc::scoped_refptr<webrtc::I420Buffer> OpenGLGraphicsDevice::ConvertRGBToI420(ITexture2D* tex)
  177. {
  178. if(!OpenGLContext::CurrentContext())
  179. contexts_.push_back(OpenGLContext::CreateGLContext(mainContext_.get()));
  180. OpenGLTexture2D* sourceTex = static_cast<OpenGLTexture2D*>(tex);
  181. const GLuint sourceId = reinterpret_cast<uintptr_t>(sourceTex->GetNativeTexturePtrV());
  182. const GLuint pbo = sourceTex->GetPBO();
  183. const GLenum format = GL_RGBA;
  184. const uint32_t width = sourceTex->GetWidth();
  185. const uint32_t height = sourceTex->GetHeight();
  186. const uint32_t bufferSize = sourceTex->GetBufferSize();
  187. byte* data = sourceTex->GetBuffer();
  188. glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
  189. glBindTexture(GL_TEXTURE_2D, sourceId);
  190. GetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, nullptr);
  191. // Send PBO to main memory
  192. GLubyte* pboPtr = static_cast<GLubyte*>(glMapBufferRange(
  193. GL_PIXEL_PACK_BUFFER, 0, bufferSize, GL_MAP_READ_BIT));
  194. if (pboPtr)
  195. {
  196. std::memcpy(data, pboPtr, bufferSize);
  197. glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
  198. }
  199. glBindTexture(GL_TEXTURE_2D, 0);
  200. glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
  201. // RGBA -> I420
  202. rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer = webrtc::I420Buffer::Create(width, height);
  203. libyuv::ABGRToI420(
  204. static_cast<uint8_t*>(data),
  205. width * 4,
  206. i420_buffer->MutableDataY(),
  207. width,
  208. i420_buffer->MutableDataU(),
  209. (width+1)/2,
  210. i420_buffer->MutableDataV(),
  211. (width+1)/2,
  212. width,
  213. height
  214. );
  215. return i420_buffer;
  216. }
  217. std::unique_ptr<GpuMemoryBufferHandle> OpenGLGraphicsDevice::Map(ITexture2D* texture)
  218. {
  219. #if CUDA_PLATFORM
  220. if(!IsCudaSupport())
  221. return nullptr;
  222. if(!OpenGLContext::CurrentContext())
  223. contexts_.push_back(OpenGLContext::CreateGLContext(mainContext_.get()));
  224. OpenGLTexture2D* glTexture2D = static_cast<OpenGLTexture2D*>(texture);
  225. CUarray mappedArray;
  226. CUgraphicsResource resource;
  227. GLuint image = glTexture2D->GetTexture();
  228. GLenum target = GL_TEXTURE_2D;
  229. // set context on the thread.
  230. cuCtxPushCurrent(GetCUcontext());
  231. CUresult result = cuGraphicsGLRegisterImage(&resource, image, target, CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST);
  232. if (result != CUDA_SUCCESS)
  233. {
  234. RTC_LOG(LS_ERROR) << "cuGraphicsD3D11RegisterResource error" << result;
  235. throw;
  236. }
  237. result = cuGraphicsMapResources(1, &resource, 0);
  238. if (result != CUDA_SUCCESS)
  239. {
  240. RTC_LOG(LS_ERROR) << "cuGraphicsMapResources";
  241. throw;
  242. }
  243. result = cuGraphicsSubResourceGetMappedArray(&mappedArray, resource, 0, 0);
  244. if (result != CUDA_SUCCESS)
  245. {
  246. RTC_LOG(LS_ERROR) << "cuGraphicsSubResourceGetMappedArray";
  247. throw;
  248. }
  249. cuCtxPopCurrent(NULL);
  250. std::unique_ptr<GpuMemoryBufferCudaHandle> handle = std::make_unique<GpuMemoryBufferCudaHandle>();
  251. handle->context = GetCUcontext();
  252. handle->mappedArray = mappedArray;
  253. handle->resource = resource;
  254. return handle;
  255. #else
  256. return nullptr;
  257. #endif
  258. }
  259. } // end namespace webrtc
  260. } // end namespace unity