1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | // Renderbuffer.cpp: the Renderbuffer class and its derived classes |
16 | // Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer |
17 | // objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. |
18 | |
19 | #include "Renderbuffer.h" |
20 | |
21 | #include "main.h" |
22 | #include "Texture.h" |
23 | #include "utilities.h" |
24 | |
25 | namespace es2 |
26 | { |
27 | RenderbufferInterface::RenderbufferInterface() |
28 | { |
29 | } |
30 | |
31 | // The default case for classes inherited from RenderbufferInterface is not to |
32 | // need to do anything upon the reference count to the parent Renderbuffer incrementing |
33 | // or decrementing. |
34 | void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy) |
35 | { |
36 | } |
37 | |
38 | void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy) |
39 | { |
40 | } |
41 | |
42 | GLuint RenderbufferInterface::getRedSize() const |
43 | { |
44 | return GetRedSize(getFormat()); |
45 | } |
46 | |
47 | GLuint RenderbufferInterface::getGreenSize() const |
48 | { |
49 | return GetGreenSize(getFormat()); |
50 | } |
51 | |
52 | GLuint RenderbufferInterface::getBlueSize() const |
53 | { |
54 | return GetBlueSize(getFormat()); |
55 | } |
56 | |
57 | GLuint RenderbufferInterface::getAlphaSize() const |
58 | { |
59 | return GetAlphaSize(getFormat()); |
60 | } |
61 | |
62 | GLuint RenderbufferInterface::getDepthSize() const |
63 | { |
64 | return GetDepthSize(getFormat()); |
65 | } |
66 | |
67 | GLuint RenderbufferInterface::getStencilSize() const |
68 | { |
69 | return GetStencilSize(getFormat()); |
70 | } |
71 | |
72 | ///// RenderbufferTexture2D Implementation //////// |
73 | |
74 | RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLint level) : mLevel(level) |
75 | { |
76 | mTexture2D = texture; |
77 | } |
78 | |
79 | RenderbufferTexture2D::~RenderbufferTexture2D() |
80 | { |
81 | mTexture2D = nullptr; |
82 | } |
83 | |
84 | // Textures need to maintain their own reference count for references via |
85 | // Renderbuffers acting as proxies. Here, we notify the texture of a reference. |
86 | void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy) |
87 | { |
88 | mTexture2D->addProxyRef(proxy); |
89 | } |
90 | |
91 | void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy) |
92 | { |
93 | mTexture2D->releaseProxy(proxy); |
94 | } |
95 | |
96 | // Increments refcount on image. |
97 | // caller must release() the returned image |
98 | egl::Image *RenderbufferTexture2D::getRenderTarget() |
99 | { |
100 | return mTexture2D->getRenderTarget(GL_TEXTURE_2D, mLevel); |
101 | } |
102 | |
103 | // Increments refcount on image. |
104 | // caller must release() the returned image |
105 | egl::Image *RenderbufferTexture2D::createSharedImage() |
106 | { |
107 | return mTexture2D->createSharedImage(GL_TEXTURE_2D, mLevel); |
108 | } |
109 | |
110 | bool RenderbufferTexture2D::isShared() const |
111 | { |
112 | return mTexture2D->isShared(GL_TEXTURE_2D, mLevel); |
113 | } |
114 | |
115 | GLsizei RenderbufferTexture2D::getWidth() const |
116 | { |
117 | return mTexture2D->getWidth(GL_TEXTURE_2D, mLevel); |
118 | } |
119 | |
120 | GLsizei RenderbufferTexture2D::getHeight() const |
121 | { |
122 | return mTexture2D->getHeight(GL_TEXTURE_2D, mLevel); |
123 | } |
124 | |
125 | GLint RenderbufferTexture2D::getFormat() const |
126 | { |
127 | return mTexture2D->getFormat(GL_TEXTURE_2D, mLevel); |
128 | } |
129 | |
130 | GLsizei RenderbufferTexture2D::getSamples() const |
131 | { |
132 | return 0; // Core OpenGL ES 3.0 does not support multisample textures. |
133 | } |
134 | |
135 | ///// RenderbufferTexture2DRect Implementation //////// |
136 | |
137 | RenderbufferTexture2DRect::RenderbufferTexture2DRect(Texture2DRect *texture) |
138 | { |
139 | mTexture2DRect = texture; |
140 | } |
141 | |
142 | RenderbufferTexture2DRect::~RenderbufferTexture2DRect() |
143 | { |
144 | mTexture2DRect = NULL; |
145 | } |
146 | |
147 | // Textures need to maintain their own reference count for references via |
148 | // Renderbuffers acting as proxies. Here, we notify the texture of a reference. |
149 | void RenderbufferTexture2DRect::addProxyRef(const Renderbuffer *proxy) |
150 | { |
151 | mTexture2DRect->addProxyRef(proxy); |
152 | } |
153 | |
154 | void RenderbufferTexture2DRect::releaseProxy(const Renderbuffer *proxy) |
155 | { |
156 | mTexture2DRect->releaseProxy(proxy); |
157 | } |
158 | |
159 | // Increments refcount on image. |
160 | // caller must release() the returned image |
161 | egl::Image *RenderbufferTexture2DRect::getRenderTarget() |
162 | { |
163 | return mTexture2DRect->getRenderTarget(GL_TEXTURE_RECTANGLE_ARB, 0); |
164 | } |
165 | |
166 | // Increments refcount on image. |
167 | // caller must release() the returned image |
168 | egl::Image *RenderbufferTexture2DRect::createSharedImage() |
169 | { |
170 | return mTexture2DRect->createSharedImage(GL_TEXTURE_RECTANGLE_ARB, 0); |
171 | } |
172 | |
173 | bool RenderbufferTexture2DRect::isShared() const |
174 | { |
175 | return mTexture2DRect->isShared(GL_TEXTURE_RECTANGLE_ARB, 0); |
176 | } |
177 | |
178 | GLsizei RenderbufferTexture2DRect::getWidth() const |
179 | { |
180 | return mTexture2DRect->getWidth(GL_TEXTURE_RECTANGLE_ARB, 0); |
181 | } |
182 | |
183 | GLsizei RenderbufferTexture2DRect::getHeight() const |
184 | { |
185 | return mTexture2DRect->getHeight(GL_TEXTURE_RECTANGLE_ARB, 0); |
186 | } |
187 | |
188 | GLint RenderbufferTexture2DRect::getFormat() const |
189 | { |
190 | return mTexture2DRect->getFormat(GL_TEXTURE_RECTANGLE_ARB, 0); |
191 | } |
192 | |
193 | GLsizei RenderbufferTexture2DRect::getSamples() const |
194 | { |
195 | return 0; // Core OpenGL ES 3.0 does not support multisample textures. |
196 | } |
197 | |
198 | ///// RenderbufferTexture3D Implementation //////// |
199 | |
200 | RenderbufferTexture3D::RenderbufferTexture3D(Texture3D *texture, GLint level) : mLevel(level) |
201 | { |
202 | mTexture3D = texture; |
203 | } |
204 | |
205 | RenderbufferTexture3D::~RenderbufferTexture3D() |
206 | { |
207 | mTexture3D = NULL; |
208 | } |
209 | |
210 | // Textures need to maintain their own reference count for references via |
211 | // Renderbuffers acting as proxies. Here, we notify the texture of a reference. |
212 | void RenderbufferTexture3D::addProxyRef(const Renderbuffer *proxy) |
213 | { |
214 | mTexture3D->addProxyRef(proxy); |
215 | } |
216 | |
217 | void RenderbufferTexture3D::releaseProxy(const Renderbuffer *proxy) |
218 | { |
219 | mTexture3D->releaseProxy(proxy); |
220 | } |
221 | |
222 | // Increments refcount on image. |
223 | // caller must release() the returned image |
224 | egl::Image *RenderbufferTexture3D::getRenderTarget() |
225 | { |
226 | return mTexture3D->getRenderTarget(mTexture3D->getTarget(), mLevel); |
227 | } |
228 | |
229 | // Increments refcount on image. |
230 | // caller must release() the returned image |
231 | egl::Image *RenderbufferTexture3D::createSharedImage() |
232 | { |
233 | return mTexture3D->createSharedImage(mTexture3D->getTarget(), mLevel); |
234 | } |
235 | |
236 | bool RenderbufferTexture3D::isShared() const |
237 | { |
238 | return mTexture3D->isShared(mTexture3D->getTarget(), mLevel); |
239 | } |
240 | |
241 | GLsizei RenderbufferTexture3D::getWidth() const |
242 | { |
243 | return mTexture3D->getWidth(mTexture3D->getTarget(), mLevel); |
244 | } |
245 | |
246 | GLsizei RenderbufferTexture3D::getHeight() const |
247 | { |
248 | return mTexture3D->getHeight(mTexture3D->getTarget(), mLevel); |
249 | } |
250 | |
251 | GLsizei RenderbufferTexture3D::getDepth() const |
252 | { |
253 | return mTexture3D->getDepth(mTexture3D->getTarget(), mLevel); |
254 | } |
255 | |
256 | GLint RenderbufferTexture3D::getFormat() const |
257 | { |
258 | return mTexture3D->getFormat(mTexture3D->getTarget(), mLevel); |
259 | } |
260 | |
261 | GLsizei RenderbufferTexture3D::getSamples() const |
262 | { |
263 | return 0; // Core OpenGL ES 3.0 does not support multisample textures. |
264 | } |
265 | |
266 | ///// RenderbufferTextureCubeMap Implementation //////// |
267 | |
268 | RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target, GLint level) : mTarget(target), mLevel(level) |
269 | { |
270 | mTextureCubeMap = texture; |
271 | } |
272 | |
273 | RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap() |
274 | { |
275 | mTextureCubeMap = NULL; |
276 | } |
277 | |
278 | // Textures need to maintain their own reference count for references via |
279 | // Renderbuffers acting as proxies. Here, we notify the texture of a reference. |
280 | void RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy) |
281 | { |
282 | mTextureCubeMap->addProxyRef(proxy); |
283 | } |
284 | |
285 | void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy) |
286 | { |
287 | mTextureCubeMap->releaseProxy(proxy); |
288 | } |
289 | |
290 | // Increments refcount on image. |
291 | // caller must release() the returned image |
292 | egl::Image *RenderbufferTextureCubeMap::getRenderTarget() |
293 | { |
294 | return mTextureCubeMap->getRenderTarget(mTarget, mLevel); |
295 | } |
296 | |
297 | // Increments refcount on image. |
298 | // caller must release() the returned image |
299 | egl::Image *RenderbufferTextureCubeMap::createSharedImage() |
300 | { |
301 | return mTextureCubeMap->createSharedImage(mTarget, mLevel); |
302 | } |
303 | |
304 | bool RenderbufferTextureCubeMap::isShared() const |
305 | { |
306 | return mTextureCubeMap->isShared(mTarget, mLevel); |
307 | } |
308 | |
309 | GLsizei RenderbufferTextureCubeMap::getWidth() const |
310 | { |
311 | return mTextureCubeMap->getWidth(mTarget, mLevel); |
312 | } |
313 | |
314 | GLsizei RenderbufferTextureCubeMap::getHeight() const |
315 | { |
316 | return mTextureCubeMap->getHeight(mTarget, mLevel); |
317 | } |
318 | |
319 | GLint RenderbufferTextureCubeMap::getFormat() const |
320 | { |
321 | return mTextureCubeMap->getFormat(mTarget, mLevel); |
322 | } |
323 | |
324 | GLsizei RenderbufferTextureCubeMap::getSamples() const |
325 | { |
326 | return 0; // Core OpenGL ES 3.0 does not support multisample textures. |
327 | } |
328 | |
329 | ////// Renderbuffer Implementation ////// |
330 | |
331 | Renderbuffer::Renderbuffer(GLuint name, RenderbufferInterface *instance) : NamedObject(name) |
332 | { |
333 | ASSERT(instance); |
334 | mInstance = instance; |
335 | } |
336 | |
337 | Renderbuffer::~Renderbuffer() |
338 | { |
339 | delete mInstance; |
340 | } |
341 | |
342 | // The RenderbufferInterface contained in this Renderbuffer may need to maintain |
343 | // its own reference count, so we pass it on here. |
344 | void Renderbuffer::addRef() |
345 | { |
346 | mInstance->addProxyRef(this); |
347 | |
348 | Object::addRef(); |
349 | } |
350 | |
351 | void Renderbuffer::release() |
352 | { |
353 | mInstance->releaseProxy(this); |
354 | |
355 | Object::release(); |
356 | } |
357 | |
358 | // Increments refcount on image. |
359 | // caller must Release() the returned image |
360 | egl::Image *Renderbuffer::getRenderTarget() |
361 | { |
362 | return mInstance->getRenderTarget(); |
363 | } |
364 | |
365 | // Increments refcount on image. |
366 | // caller must Release() the returned image |
367 | egl::Image *Renderbuffer::createSharedImage() |
368 | { |
369 | return mInstance->createSharedImage(); |
370 | } |
371 | |
372 | bool Renderbuffer::isShared() const |
373 | { |
374 | return mInstance->isShared(); |
375 | } |
376 | |
377 | GLsizei Renderbuffer::getWidth() const |
378 | { |
379 | return mInstance->getWidth(); |
380 | } |
381 | |
382 | GLsizei Renderbuffer::getHeight() const |
383 | { |
384 | return mInstance->getHeight(); |
385 | } |
386 | |
387 | GLsizei Renderbuffer::getDepth() const |
388 | { |
389 | return mInstance->getDepth(); |
390 | } |
391 | |
392 | GLint Renderbuffer::getLevel() const |
393 | { |
394 | return mInstance->getLevel(); |
395 | } |
396 | |
397 | GLint Renderbuffer::getFormat() const |
398 | { |
399 | return mInstance->getFormat(); |
400 | } |
401 | |
402 | GLuint Renderbuffer::getRedSize() const |
403 | { |
404 | return mInstance->getRedSize(); |
405 | } |
406 | |
407 | GLuint Renderbuffer::getGreenSize() const |
408 | { |
409 | return mInstance->getGreenSize(); |
410 | } |
411 | |
412 | GLuint Renderbuffer::getBlueSize() const |
413 | { |
414 | return mInstance->getBlueSize(); |
415 | } |
416 | |
417 | GLuint Renderbuffer::getAlphaSize() const |
418 | { |
419 | return mInstance->getAlphaSize(); |
420 | } |
421 | |
422 | GLuint Renderbuffer::getDepthSize() const |
423 | { |
424 | return mInstance->getDepthSize(); |
425 | } |
426 | |
427 | GLuint Renderbuffer::getStencilSize() const |
428 | { |
429 | return mInstance->getStencilSize(); |
430 | } |
431 | |
432 | GLsizei Renderbuffer::getSamples() const |
433 | { |
434 | return mInstance->getSamples(); |
435 | } |
436 | |
437 | void Renderbuffer::setLevel(GLint level) |
438 | { |
439 | return mInstance->setLevel(level); |
440 | } |
441 | |
442 | void Renderbuffer::setStorage(RenderbufferStorage *newStorage) |
443 | { |
444 | ASSERT(newStorage); |
445 | |
446 | delete mInstance; |
447 | mInstance = newStorage; |
448 | } |
449 | |
450 | RenderbufferStorage::RenderbufferStorage() |
451 | { |
452 | mWidth = 0; |
453 | mHeight = 0; |
454 | format = GL_NONE; |
455 | mSamples = 0; |
456 | } |
457 | |
458 | RenderbufferStorage::~RenderbufferStorage() |
459 | { |
460 | } |
461 | |
462 | GLsizei RenderbufferStorage::getWidth() const |
463 | { |
464 | return mWidth; |
465 | } |
466 | |
467 | GLsizei RenderbufferStorage::getHeight() const |
468 | { |
469 | return mHeight; |
470 | } |
471 | |
472 | GLint RenderbufferStorage::getFormat() const |
473 | { |
474 | return format; |
475 | } |
476 | |
477 | GLsizei RenderbufferStorage::getSamples() const |
478 | { |
479 | return mSamples; |
480 | } |
481 | |
482 | Colorbuffer::Colorbuffer(egl::Image *renderTarget) : mRenderTarget(renderTarget) |
483 | { |
484 | if(renderTarget) |
485 | { |
486 | renderTarget->addRef(); |
487 | |
488 | mWidth = renderTarget->getWidth(); |
489 | mHeight = renderTarget->getHeight(); |
490 | format = renderTarget->getFormat(); |
491 | mSamples = renderTarget->getDepth() & ~1; |
492 | } |
493 | } |
494 | |
495 | Colorbuffer::Colorbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mRenderTarget(nullptr) |
496 | { |
497 | int supportedSamples = Context::getSupportedMultisampleCount(samples); |
498 | |
499 | if(width > 0 && height > 0) |
500 | { |
501 | if(height > sw::OUTLINE_RESOLUTION) |
502 | { |
503 | error(GL_OUT_OF_MEMORY); |
504 | return; |
505 | } |
506 | |
507 | mRenderTarget = egl::Image::create(width, height, internalformat, supportedSamples, false); |
508 | |
509 | if(!mRenderTarget) |
510 | { |
511 | error(GL_OUT_OF_MEMORY); |
512 | return; |
513 | } |
514 | } |
515 | |
516 | mWidth = width; |
517 | mHeight = height; |
518 | format = internalformat; |
519 | mSamples = supportedSamples; |
520 | } |
521 | |
522 | Colorbuffer::~Colorbuffer() |
523 | { |
524 | if(mRenderTarget) |
525 | { |
526 | mRenderTarget->release(); |
527 | } |
528 | } |
529 | |
530 | // Increments refcount on image. |
531 | // caller must release() the returned image |
532 | egl::Image *Colorbuffer::getRenderTarget() |
533 | { |
534 | if(mRenderTarget) |
535 | { |
536 | mRenderTarget->addRef(); |
537 | } |
538 | |
539 | return mRenderTarget; |
540 | } |
541 | |
542 | // Increments refcount on image. |
543 | // caller must release() the returned image |
544 | egl::Image *Colorbuffer::createSharedImage() |
545 | { |
546 | if(mRenderTarget) |
547 | { |
548 | mRenderTarget->addRef(); |
549 | mRenderTarget->markShared(); |
550 | } |
551 | |
552 | return mRenderTarget; |
553 | } |
554 | |
555 | bool Colorbuffer::isShared() const |
556 | { |
557 | return mRenderTarget->isShared(); |
558 | } |
559 | |
560 | DepthStencilbuffer::DepthStencilbuffer(egl::Image *depthStencil) : mDepthStencil(depthStencil) |
561 | { |
562 | if(depthStencil) |
563 | { |
564 | depthStencil->addRef(); |
565 | |
566 | mWidth = depthStencil->getWidth(); |
567 | mHeight = depthStencil->getHeight(); |
568 | format = depthStencil->getFormat(); |
569 | mSamples = depthStencil->getDepth() & ~1; |
570 | } |
571 | } |
572 | |
573 | DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mDepthStencil(nullptr) |
574 | { |
575 | int supportedSamples = Context::getSupportedMultisampleCount(samples); |
576 | |
577 | if(width > 0 && height > 0) |
578 | { |
579 | if(height > sw::OUTLINE_RESOLUTION) |
580 | { |
581 | error(GL_OUT_OF_MEMORY); |
582 | return; |
583 | } |
584 | |
585 | mDepthStencil = egl::Image::create(width, height, internalformat, supportedSamples, false); |
586 | |
587 | if(!mDepthStencil) |
588 | { |
589 | error(GL_OUT_OF_MEMORY); |
590 | return; |
591 | } |
592 | } |
593 | |
594 | mWidth = width; |
595 | mHeight = height; |
596 | format = internalformat; |
597 | mSamples = supportedSamples; |
598 | } |
599 | |
600 | DepthStencilbuffer::~DepthStencilbuffer() |
601 | { |
602 | if(mDepthStencil) |
603 | { |
604 | mDepthStencil->release(); |
605 | } |
606 | } |
607 | |
608 | // Increments refcount on image. |
609 | // caller must release() the returned image |
610 | egl::Image *DepthStencilbuffer::getRenderTarget() |
611 | { |
612 | if(mDepthStencil) |
613 | { |
614 | mDepthStencil->addRef(); |
615 | } |
616 | |
617 | return mDepthStencil; |
618 | } |
619 | |
620 | // Increments refcount on image. |
621 | // caller must release() the returned image |
622 | egl::Image *DepthStencilbuffer::createSharedImage() |
623 | { |
624 | if(mDepthStencil) |
625 | { |
626 | mDepthStencil->addRef(); |
627 | mDepthStencil->markShared(); |
628 | } |
629 | |
630 | return mDepthStencil; |
631 | } |
632 | |
633 | bool DepthStencilbuffer::isShared() const |
634 | { |
635 | return mDepthStencil->isShared(); |
636 | } |
637 | |
638 | Depthbuffer::Depthbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil) |
639 | { |
640 | } |
641 | |
642 | Depthbuffer::Depthbuffer(int width, int height, GLenum internalformat, GLsizei samples) : DepthStencilbuffer(width, height, internalformat, samples) |
643 | { |
644 | } |
645 | |
646 | Depthbuffer::~Depthbuffer() |
647 | { |
648 | } |
649 | |
650 | Stencilbuffer::Stencilbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil) |
651 | { |
652 | } |
653 | |
654 | Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, GL_STENCIL_INDEX8, samples) |
655 | { |
656 | } |
657 | |
658 | Stencilbuffer::~Stencilbuffer() |
659 | { |
660 | } |
661 | |
662 | } |
663 | |