1 //
2 // Copyright 2002 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
7 // Renderbuffer.cpp: Implements the renderer-agnostic gl::Renderbuffer class,
8 // GL renderbuffer objects and related functionality.
9 // [OpenGL ES 2.0.24] section 4.4.3 page 108.
10
11 #include "libANGLE/Renderbuffer.h"
12
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/Image.h"
17 #include "libANGLE/Renderbuffer.h"
18 #include "libANGLE/Texture.h"
19 #include "libANGLE/formatutils.h"
20 #include "libANGLE/renderer/GLImplFactory.h"
21
22 namespace gl
23 {
24 namespace
25 {
26 angle::SubjectIndex kRenderbufferImplSubjectIndex = 0;
27
DetermineInitState(const Context * context)28 InitState DetermineInitState(const Context *context)
29 {
30 return (context && context->isRobustResourceInitEnabled()) ? InitState::MayNeedInit
31 : InitState::Initialized;
32 }
33 } // namespace
34
35 // RenderbufferState implementation.
RenderbufferState()36 RenderbufferState::RenderbufferState()
37 : mWidth(0),
38 mHeight(0),
39 mFormat(GL_RGBA4),
40 mSamples(0),
41 mMultisamplingMode(MultisamplingMode::Regular),
42 mHasProtectedContent(false),
43 mInitState(InitState::Initialized)
44 {}
45
~RenderbufferState()46 RenderbufferState::~RenderbufferState() {}
47
getWidth() const48 GLsizei RenderbufferState::getWidth() const
49 {
50 return mWidth;
51 }
52
getHeight() const53 GLsizei RenderbufferState::getHeight() const
54 {
55 return mHeight;
56 }
57
getFormat() const58 const Format &RenderbufferState::getFormat() const
59 {
60 return mFormat;
61 }
62
getSamples() const63 GLsizei RenderbufferState::getSamples() const
64 {
65 return mSamples;
66 }
67
getMultisamplingMode() const68 MultisamplingMode RenderbufferState::getMultisamplingMode() const
69 {
70 return mMultisamplingMode;
71 }
72
getInitState() const73 InitState RenderbufferState::getInitState() const
74 {
75 return mInitState;
76 }
77
update(GLsizei width,GLsizei height,const Format & format,GLsizei samples,MultisamplingMode multisamplingMode,InitState initState)78 void RenderbufferState::update(GLsizei width,
79 GLsizei height,
80 const Format &format,
81 GLsizei samples,
82 MultisamplingMode multisamplingMode,
83 InitState initState)
84 {
85 mWidth = width;
86 mHeight = height;
87 mFormat = format;
88 mSamples = samples;
89 mMultisamplingMode = multisamplingMode;
90 mInitState = initState;
91 mHasProtectedContent = false;
92 }
93
setProtectedContent(bool hasProtectedContent)94 void RenderbufferState::setProtectedContent(bool hasProtectedContent)
95 {
96 mHasProtectedContent = hasProtectedContent;
97 }
98
99 // Renderbuffer implementation.
Renderbuffer(rx::GLImplFactory * implFactory,RenderbufferID id)100 Renderbuffer::Renderbuffer(rx::GLImplFactory *implFactory, RenderbufferID id)
101 : RefCountObject(implFactory->generateSerial(), id),
102 mState(),
103 mImplementation(implFactory->createRenderbuffer(mState)),
104 mLabel(),
105 mImplObserverBinding(this, kRenderbufferImplSubjectIndex)
106 {
107 mImplObserverBinding.bind(mImplementation.get());
108 }
109
onDestroy(const Context * context)110 void Renderbuffer::onDestroy(const Context *context)
111 {
112 egl::RefCountObjectReleaser<egl::Image> releaseImage;
113 (void)orphanImages(context, &releaseImage);
114
115 if (mImplementation)
116 {
117 mImplementation->onDestroy(context);
118 }
119 }
120
~Renderbuffer()121 Renderbuffer::~Renderbuffer() {}
122
setLabel(const Context * context,const std::string & label)123 angle::Result Renderbuffer::setLabel(const Context *context, const std::string &label)
124 {
125 mLabel = label;
126
127 if (mImplementation)
128 {
129 return mImplementation->onLabelUpdate(context);
130 }
131 return angle::Result::Continue;
132 }
133
getLabel() const134 const std::string &Renderbuffer::getLabel() const
135 {
136 return mLabel;
137 }
138
setStorage(const Context * context,GLenum internalformat,GLsizei width,GLsizei height)139 angle::Result Renderbuffer::setStorage(const Context *context,
140 GLenum internalformat,
141 GLsizei width,
142 GLsizei height)
143 {
144
145 egl::RefCountObjectReleaser<egl::Image> releaseImage;
146 ANGLE_TRY(orphanImages(context, &releaseImage));
147
148 ANGLE_TRY(mImplementation->setStorage(context, internalformat, width, height));
149
150 mState.update(width, height, Format(internalformat), 0, MultisamplingMode::Regular,
151 DetermineInitState(context));
152 onStateChange(angle::SubjectMessage::SubjectChanged);
153
154 return angle::Result::Continue;
155 }
156
setStorageMultisample(const Context * context,GLsizei samplesIn,GLenum internalformat,GLsizei width,GLsizei height,MultisamplingMode mode)157 angle::Result Renderbuffer::setStorageMultisample(const Context *context,
158 GLsizei samplesIn,
159 GLenum internalformat,
160 GLsizei width,
161 GLsizei height,
162 MultisamplingMode mode)
163 {
164 egl::RefCountObjectReleaser<egl::Image> releaseImage;
165 ANGLE_TRY(orphanImages(context, &releaseImage));
166
167 // Potentially adjust "samplesIn" to a supported value
168 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
169 GLsizei samples = formatCaps.getNearestSamples(samplesIn);
170
171 ANGLE_TRY(mImplementation->setStorageMultisample(context, samples, internalformat, width,
172 height, mode));
173
174 mState.update(width, height, Format(internalformat), samples, mode,
175 DetermineInitState(context));
176 onStateChange(angle::SubjectMessage::SubjectChanged);
177
178 return angle::Result::Continue;
179 }
180
setStorageEGLImageTarget(const Context * context,egl::Image * image)181 angle::Result Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image *image)
182 {
183 egl::RefCountObjectReleaser<egl::Image> releaseImage;
184 ANGLE_TRY(orphanImages(context, &releaseImage));
185
186 ANGLE_TRY(mImplementation->setStorageEGLImageTarget(context, image));
187
188 setTargetImage(context, image);
189
190 mState.update(static_cast<GLsizei>(image->getWidth()), static_cast<GLsizei>(image->getHeight()),
191 Format(image->getFormat()), 0, MultisamplingMode::Regular,
192 image->sourceInitState());
193 mState.setProtectedContent(image->hasProtectedContent());
194
195 onStateChange(angle::SubjectMessage::SubjectChanged);
196
197 return angle::Result::Continue;
198 }
199
copyRenderbufferSubData(Context * context,const gl::Renderbuffer * srcBuffer,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)200 angle::Result Renderbuffer::copyRenderbufferSubData(Context *context,
201 const gl::Renderbuffer *srcBuffer,
202 GLint srcLevel,
203 GLint srcX,
204 GLint srcY,
205 GLint srcZ,
206 GLint dstLevel,
207 GLint dstX,
208 GLint dstY,
209 GLint dstZ,
210 GLsizei srcWidth,
211 GLsizei srcHeight,
212 GLsizei srcDepth)
213 {
214 ANGLE_TRY(mImplementation->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY,
215 srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
216 srcHeight, srcDepth));
217
218 return angle::Result::Continue;
219 }
220
copyTextureSubData(Context * context,const gl::Texture * srcTexture,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)221 angle::Result Renderbuffer::copyTextureSubData(Context *context,
222 const gl::Texture *srcTexture,
223 GLint srcLevel,
224 GLint srcX,
225 GLint srcY,
226 GLint srcZ,
227 GLint dstLevel,
228 GLint dstX,
229 GLint dstY,
230 GLint dstZ,
231 GLsizei srcWidth,
232 GLsizei srcHeight,
233 GLsizei srcDepth)
234 {
235 ANGLE_TRY(mImplementation->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
236 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
237 srcDepth));
238
239 return angle::Result::Continue;
240 }
241
getImplementation() const242 rx::RenderbufferImpl *Renderbuffer::getImplementation() const
243 {
244 ASSERT(mImplementation);
245 return mImplementation.get();
246 }
247
getWidth() const248 GLsizei Renderbuffer::getWidth() const
249 {
250 return mState.mWidth;
251 }
252
getHeight() const253 GLsizei Renderbuffer::getHeight() const
254 {
255 return mState.mHeight;
256 }
257
getFormat() const258 const Format &Renderbuffer::getFormat() const
259 {
260 return mState.mFormat;
261 }
262
getSamples() const263 GLsizei Renderbuffer::getSamples() const
264 {
265 return mState.mMultisamplingMode == MultisamplingMode::Regular ? mState.mSamples : 0;
266 }
267
getMultisamplingMode() const268 MultisamplingMode Renderbuffer::getMultisamplingMode() const
269 {
270 return mState.mMultisamplingMode;
271 }
272
getRedSize() const273 GLuint Renderbuffer::getRedSize() const
274 {
275 return mState.mFormat.info->redBits;
276 }
277
getGreenSize() const278 GLuint Renderbuffer::getGreenSize() const
279 {
280 return mState.mFormat.info->greenBits;
281 }
282
getBlueSize() const283 GLuint Renderbuffer::getBlueSize() const
284 {
285 return mState.mFormat.info->blueBits;
286 }
287
getAlphaSize() const288 GLuint Renderbuffer::getAlphaSize() const
289 {
290 return mState.mFormat.info->alphaBits;
291 }
292
getDepthSize() const293 GLuint Renderbuffer::getDepthSize() const
294 {
295 return mState.mFormat.info->depthBits;
296 }
297
getStencilSize() const298 GLuint Renderbuffer::getStencilSize() const
299 {
300 return mState.mFormat.info->stencilBits;
301 }
302
getState() const303 const RenderbufferState &Renderbuffer::getState() const
304 {
305 return mState;
306 }
307
getMemorySize() const308 GLint Renderbuffer::getMemorySize() const
309 {
310 GLint implSize = mImplementation->getMemorySize();
311 if (implSize > 0)
312 {
313 return implSize;
314 }
315
316 // Assume allocated size is around width * height * samples * pixelBytes
317 angle::CheckedNumeric<GLint> size = 1;
318 size *= mState.mFormat.info->pixelBytes;
319 size *= mState.mWidth;
320 size *= mState.mHeight;
321 size *= std::max(mState.mSamples, 1);
322 return size.ValueOrDefault(std::numeric_limits<GLint>::max());
323 }
324
onAttach(const Context * context,rx::UniqueSerial framebufferSerial)325 void Renderbuffer::onAttach(const Context *context, rx::UniqueSerial framebufferSerial)
326 {
327 addRef();
328 }
329
onDetach(const Context * context,rx::UniqueSerial framebufferSerial)330 void Renderbuffer::onDetach(const Context *context, rx::UniqueSerial framebufferSerial)
331 {
332 release(context);
333 }
334
getId() const335 GLuint Renderbuffer::getId() const
336 {
337 return id().value;
338 }
339
getAttachmentSize(const gl::ImageIndex &) const340 Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) const
341 {
342 return Extents(mState.mWidth, mState.mHeight, 1);
343 }
344
getAttachmentFormat(GLenum,const ImageIndex &) const345 Format Renderbuffer::getAttachmentFormat(GLenum /*binding*/,
346 const ImageIndex & /*imageIndex*/) const
347 {
348 return getFormat();
349 }
getAttachmentSamples(const ImageIndex &) const350 GLsizei Renderbuffer::getAttachmentSamples(const ImageIndex & /*imageIndex*/) const
351 {
352 return getSamples();
353 }
354
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const355 bool Renderbuffer::isRenderable(const Context *context,
356 GLenum binding,
357 const ImageIndex &imageIndex) const
358 {
359 if (isEGLImageTarget())
360 {
361 return ImageSibling::isRenderable(context, binding, imageIndex);
362 }
363 return getFormat().info->renderbufferSupport(context->getClientVersion(),
364 context->getExtensions());
365 }
366
initState(GLenum,const gl::ImageIndex &) const367 InitState Renderbuffer::initState(GLenum /*binding*/, const gl::ImageIndex & /*imageIndex*/) const
368 {
369 if (isEGLImageTarget())
370 {
371 return sourceEGLImageInitState();
372 }
373
374 return mState.mInitState;
375 }
376
setInitState(GLenum,const gl::ImageIndex &,InitState initState)377 void Renderbuffer::setInitState(GLenum /*binding*/,
378 const gl::ImageIndex & /*imageIndex*/,
379 InitState initState)
380 {
381 if (isEGLImageTarget())
382 {
383 setSourceEGLImageInitState(initState);
384 }
385 else
386 {
387 mState.mInitState = initState;
388 }
389 }
390
getAttachmentImpl() const391 rx::FramebufferAttachmentObjectImpl *Renderbuffer::getAttachmentImpl() const
392 {
393 return mImplementation.get();
394 }
395
getImplementationColorReadFormat(const Context * context) const396 GLenum Renderbuffer::getImplementationColorReadFormat(const Context *context) const
397 {
398 return mImplementation->getColorReadFormat(context);
399 }
400
getImplementationColorReadType(const Context * context) const401 GLenum Renderbuffer::getImplementationColorReadType(const Context *context) const
402 {
403 return mImplementation->getColorReadType(context);
404 }
405
getRenderbufferImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,GLenum format,GLenum type,void * pixels) const406 angle::Result Renderbuffer::getRenderbufferImage(const Context *context,
407 const PixelPackState &packState,
408 Buffer *packBuffer,
409 GLenum format,
410 GLenum type,
411 void *pixels) const
412 {
413 return mImplementation->getRenderbufferImage(context, packState, packBuffer, format, type,
414 pixels);
415 }
416
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)417 void Renderbuffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
418 {
419 ASSERT(message == angle::SubjectMessage::SubjectChanged);
420 onStateChange(angle::SubjectMessage::ContentsChanged);
421 }
422 } // namespace gl
423