WebGLRenderbuffer.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "WebGLRenderbuffer.h"
  6. #include "GLContext.h"
  7. #include "mozilla/dom/WebGLRenderingContextBinding.h"
  8. #include "ScopedGLHelpers.h"
  9. #include "WebGLContext.h"
  10. #include "WebGLStrongTypes.h"
  11. #include "WebGLTexture.h"
  12. namespace mozilla {
  13. static GLenum
  14. DepthFormatForDepthStencilEmu(gl::GLContext* gl)
  15. {
  16. // We might not be able to get 24-bit, so let's pretend!
  17. if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
  18. return LOCAL_GL_DEPTH_COMPONENT16;
  19. return LOCAL_GL_DEPTH_COMPONENT24;
  20. }
  21. JSObject*
  22. WebGLRenderbuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
  23. {
  24. return dom::WebGLRenderbufferBinding::Wrap(cx, this, givenProto);
  25. }
  26. static GLuint
  27. DoCreateRenderbuffer(gl::GLContext* gl)
  28. {
  29. MOZ_ASSERT(gl->IsCurrent());
  30. GLuint ret = 0;
  31. gl->fGenRenderbuffers(1, &ret);
  32. return ret;
  33. }
  34. static bool
  35. EmulatePackedDepthStencil(gl::GLContext* gl)
  36. {
  37. return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
  38. }
  39. WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
  40. : WebGLRefCountedObject(webgl)
  41. , mPrimaryRB( DoCreateRenderbuffer(webgl->gl) )
  42. , mEmulatePackedDepthStencil( EmulatePackedDepthStencil(webgl->gl) )
  43. , mSecondaryRB(0)
  44. , mFormat(nullptr)
  45. , mSamples(0)
  46. , mImageDataStatus(WebGLImageDataStatus::NoImageData)
  47. , mHasBeenBound(false)
  48. {
  49. mContext->mRenderbuffers.insertBack(this);
  50. }
  51. void
  52. WebGLRenderbuffer::Delete()
  53. {
  54. mContext->MakeContextCurrent();
  55. mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
  56. if (mSecondaryRB)
  57. mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
  58. LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
  59. }
  60. int64_t
  61. WebGLRenderbuffer::MemoryUsage() const
  62. {
  63. // If there is no defined format, we're not taking up any memory
  64. if (!mFormat)
  65. return 0;
  66. const auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
  67. const int64_t pixels = int64_t(mWidth) * int64_t(mHeight);
  68. const int64_t totalSize = pixels * bytesPerPixel;
  69. return totalSize;
  70. }
  71. static GLenum
  72. DoRenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
  73. GLenum internalFormat, GLsizei width,
  74. GLsizei height)
  75. {
  76. MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
  77. // Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL.
  78. switch (internalFormat) {
  79. case LOCAL_GL_RGBA4:
  80. case LOCAL_GL_RGB5_A1:
  81. // 16-bit RGBA formats are not supported on desktop GL.
  82. if (!gl->IsGLES())
  83. internalFormat = LOCAL_GL_RGBA8;
  84. break;
  85. case LOCAL_GL_RGB565:
  86. // RGB565 is not supported on desktop GL.
  87. if (!gl->IsGLES())
  88. internalFormat = LOCAL_GL_RGB8;
  89. break;
  90. case LOCAL_GL_DEPTH_COMPONENT16:
  91. if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
  92. internalFormat = LOCAL_GL_DEPTH_COMPONENT24;
  93. else if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
  94. internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
  95. break;
  96. case LOCAL_GL_DEPTH_STENCIL:
  97. MOZ_CRASH("GFX: GL_DEPTH_STENCIL is not valid here.");
  98. break;
  99. default:
  100. break;
  101. }
  102. gl::GLContext::LocalErrorScope errorScope(*gl);
  103. if (samples > 0) {
  104. gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
  105. internalFormat, width, height);
  106. } else {
  107. gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width, height);
  108. }
  109. return errorScope.GetError();
  110. }
  111. GLenum
  112. WebGLRenderbuffer::DoRenderbufferStorage(uint32_t samples,
  113. const webgl::FormatUsageInfo* format,
  114. uint32_t width, uint32_t height)
  115. {
  116. MOZ_ASSERT(mContext->mBoundRenderbuffer == this);
  117. gl::GLContext* gl = mContext->gl;
  118. MOZ_ASSERT(samples <= 256); // Sanity check.
  119. GLenum primaryFormat = format->format->sizedFormat;
  120. GLenum secondaryFormat = 0;
  121. if (mEmulatePackedDepthStencil && primaryFormat == LOCAL_GL_DEPTH24_STENCIL8) {
  122. primaryFormat = DepthFormatForDepthStencilEmu(gl);
  123. secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
  124. }
  125. gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
  126. GLenum error = DoRenderbufferStorageMaybeMultisample(gl, samples, primaryFormat,
  127. width, height);
  128. if (error)
  129. return error;
  130. if (secondaryFormat) {
  131. if (!mSecondaryRB) {
  132. gl->fGenRenderbuffers(1, &mSecondaryRB);
  133. }
  134. gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mSecondaryRB);
  135. error = DoRenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat,
  136. width, height);
  137. if (error)
  138. return error;
  139. } else if (mSecondaryRB) {
  140. gl->fDeleteRenderbuffers(1, &mSecondaryRB);
  141. mSecondaryRB = 0;
  142. }
  143. return 0;
  144. }
  145. void
  146. WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
  147. GLenum internalFormat, uint32_t width,
  148. uint32_t height)
  149. {
  150. const auto usage = mContext->mFormatUsage->GetRBUsage(internalFormat);
  151. if (!usage) {
  152. mContext->ErrorInvalidEnum("%s: Invalid `internalFormat`: 0x%04x.", funcName,
  153. internalFormat);
  154. return;
  155. }
  156. if (width > mContext->mImplMaxRenderbufferSize ||
  157. height > mContext->mImplMaxRenderbufferSize)
  158. {
  159. mContext->ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
  160. " size.",
  161. funcName);
  162. return;
  163. }
  164. mContext->MakeContextCurrent();
  165. if (!usage->maxSamplesKnown) {
  166. const_cast<webgl::FormatUsageInfo*>(usage)->ResolveMaxSamples(mContext->gl);
  167. }
  168. MOZ_ASSERT(usage->maxSamplesKnown);
  169. if (samples > usage->maxSamples) {
  170. mContext->ErrorInvalidOperation("%s: `samples` is out of the valid range.", funcName);
  171. return;
  172. }
  173. // Validation complete.
  174. const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
  175. if (error) {
  176. const char* errorName = mContext->ErrorName(error);
  177. mContext->GenerateWarning("%s generated error %s", funcName, errorName);
  178. if (error == LOCAL_GL_OUT_OF_MEMORY) {
  179. // Truncate.
  180. mSamples = 0;
  181. mFormat = nullptr;
  182. mWidth = 0;
  183. mHeight = 0;
  184. mImageDataStatus = WebGLImageDataStatus::NoImageData;
  185. InvalidateStatusOfAttachedFBs();
  186. }
  187. return;
  188. }
  189. mSamples = samples;
  190. mFormat = usage;
  191. mWidth = width;
  192. mHeight = height;
  193. mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
  194. InvalidateStatusOfAttachedFBs();
  195. }
  196. void
  197. WebGLRenderbuffer::DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const
  198. {
  199. gl::GLContext* gl = mContext->gl;
  200. if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
  201. const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
  202. gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_DEPTH_ATTACHMENT,
  203. LOCAL_GL_RENDERBUFFER, mPrimaryRB);
  204. gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_STENCIL_ATTACHMENT,
  205. LOCAL_GL_RENDERBUFFER, stencilRB);
  206. return;
  207. }
  208. gl->fFramebufferRenderbuffer(target.get(), attachment,
  209. LOCAL_GL_RENDERBUFFER, mPrimaryRB);
  210. }
  211. GLint
  212. WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
  213. RBParam pname) const
  214. {
  215. gl::GLContext* gl = mContext->gl;
  216. switch (pname.get()) {
  217. case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
  218. if (!mFormat)
  219. return 0;
  220. if (!mFormat->format->s)
  221. return 0;
  222. return 8;
  223. case LOCAL_GL_RENDERBUFFER_SAMPLES:
  224. case LOCAL_GL_RENDERBUFFER_WIDTH:
  225. case LOCAL_GL_RENDERBUFFER_HEIGHT:
  226. case LOCAL_GL_RENDERBUFFER_RED_SIZE:
  227. case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
  228. case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
  229. case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
  230. case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
  231. {
  232. gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
  233. GLint i = 0;
  234. gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
  235. return i;
  236. }
  237. case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
  238. {
  239. GLenum ret = LOCAL_GL_RGBA4;
  240. if (mFormat) {
  241. ret = mFormat->format->sizedFormat;
  242. if (!mContext->IsWebGL2() && ret == LOCAL_GL_DEPTH24_STENCIL8) {
  243. ret = LOCAL_GL_DEPTH_STENCIL;
  244. }
  245. }
  246. return ret;
  247. }
  248. }
  249. MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
  250. return 0;
  251. }
  252. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
  253. NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
  254. NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)
  255. } // namespace mozilla