blob: e19bffa8aea509de1ef094a157f977c1c4d8e822 [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
2// Copyright 2015 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// FramebufferGL.cpp: Implements the class methods for FramebufferGL.
8
9#include "libANGLE/renderer/gl/FramebufferGL.h"
10
Jamie Madill20e005b2017-04-07 14:19:22 -040011#include "common/bitset_utils.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050012#include "common/debug.h"
Geoff Lang4ad17092015-03-10 16:47:44 -040013#include "libANGLE/FramebufferAttachment.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040014#include "libANGLE/State.h"
Geoff Lang4ad17092015-03-10 16:47:44 -040015#include "libANGLE/angletypes.h"
16#include "libANGLE/formatutils.h"
Geoff Lang92019432017-11-20 13:09:34 -050017#include "libANGLE/queryconversions.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040018#include "libANGLE/renderer/ContextImpl.h"
Corentin Wallez26a717b2016-09-27 08:45:42 -070019#include "libANGLE/renderer/gl/BlitGL.h"
Martin Radev5e424fa2017-08-09 16:25:36 +030020#include "libANGLE/renderer/gl/ClearMultiviewGL.h"
Frank Henigmanfa36c332017-06-09 18:44:45 -040021#include "libANGLE/renderer/gl/ContextGL.h"
Geoff Lang4ad17092015-03-10 16:47:44 -040022#include "libANGLE/renderer/gl/FunctionsGL.h"
Jacek Cabanfa60f692015-04-27 18:23:44 +020023#include "libANGLE/renderer/gl/RenderbufferGL.h"
Geoff Lang4ad17092015-03-10 16:47:44 -040024#include "libANGLE/renderer/gl/StateManagerGL.h"
25#include "libANGLE/renderer/gl/TextureGL.h"
Geoff Langf607c602016-09-21 11:46:48 -040026#include "libANGLE/renderer/gl/formatutilsgl.h"
Corentin Wallez886de362016-09-27 10:49:35 -040027#include "libANGLE/renderer/gl/renderergl_utils.h"
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -040028#include "platform/FeaturesGL.h"
Jamie Madillcc86d642015-11-24 13:00:07 -050029#include "platform/Platform.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050030
Jamie Madill60ec6ea2016-01-22 15:27:19 -050031using namespace gl;
Corentin Wallez9a8d3662016-09-22 12:18:29 -040032using angle::CheckedNumeric;
Jamie Madill60ec6ea2016-01-22 15:27:19 -050033
Geoff Langf9a6f082015-01-22 13:32:49 -050034namespace rx
35{
36
Martin Radev878c8b12017-07-28 09:51:04 +030037namespace
Geoff Lang4ad17092015-03-10 16:47:44 -040038{
Geoff Langf9a6f082015-01-22 13:32:49 -050039
Martin Radev878c8b12017-07-28 09:51:04 +030040void BindFramebufferAttachment(const FunctionsGL *functions,
41 GLenum attachmentPoint,
42 const FramebufferAttachment *attachment)
Geoff Lang4ad17092015-03-10 16:47:44 -040043{
44 if (attachment)
45 {
46 if (attachment->type() == GL_TEXTURE)
47 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -050048 const Texture *texture = attachment->getTexture();
Geoff Lang4ad17092015-03-10 16:47:44 -040049 const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
50
Corentin Wallez99d492c2018-02-27 15:17:10 -050051 if (texture->getType() == TextureType::_2D ||
52 texture->getType() == TextureType::_2DMultisample ||
53 texture->getType() == TextureType::Rectangle)
Geoff Lang4ad17092015-03-10 16:47:44 -040054 {
JiangYizhoubddc46b2016-12-09 09:50:51 +080055 functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint,
Corentin Wallez99d492c2018-02-27 15:17:10 -050056 ToGLenum(texture->getType()),
Geoff Lang4ad17092015-03-10 16:47:44 -040057 textureGL->getTextureID(), attachment->mipLevel());
58 }
Jiawei Shaoa8802472018-05-28 11:17:47 +080059 else if (attachment->isLayered())
60 {
61 TextureType textureType = texture->getType();
62 ASSERT(textureType == TextureType::_2DArray || textureType == TextureType::_3D ||
Olli Etuahodff32a02018-08-28 14:35:50 +030063 textureType == TextureType::CubeMap ||
64 textureType == TextureType::_2DMultisampleArray);
Jiawei Shaoa8802472018-05-28 11:17:47 +080065 functions->framebufferTexture(GL_FRAMEBUFFER, attachmentPoint,
66 textureGL->getTextureID(), attachment->mipLevel());
67 }
Corentin Wallez99d492c2018-02-27 15:17:10 -050068 else if (texture->getType() == TextureType::CubeMap)
69 {
70 functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint,
71 ToGLenum(attachment->cubeMapFace()),
72 textureGL->getTextureID(), attachment->mipLevel());
73 }
74 else if (texture->getType() == TextureType::_2DArray ||
Olli Etuahofd162102018-08-27 16:14:57 +030075 texture->getType() == TextureType::_3D ||
76 texture->getType() == TextureType::_2DMultisampleArray)
Geoff Lang4ad17092015-03-10 16:47:44 -040077 {
Mingyu Hu7d64c482019-03-12 14:27:40 -070078 if (attachment->isMultiview())
Martin Radev5e424fa2017-08-09 16:25:36 +030079 {
80 ASSERT(functions->framebufferTexture);
81 functions->framebufferTexture(GL_FRAMEBUFFER, attachmentPoint,
82 textureGL->getTextureID(),
83 attachment->mipLevel());
84 }
85 else
86 {
87 functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint,
88 textureGL->getTextureID(),
89 attachment->mipLevel(), attachment->layer());
90 }
Geoff Lang4ad17092015-03-10 16:47:44 -040091 }
92 else
93 {
94 UNREACHABLE();
95 }
96 }
97 else if (attachment->type() == GL_RENDERBUFFER)
98 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -050099 const Renderbuffer *renderbuffer = attachment->getRenderbuffer();
Geoff Langcd69f1c2015-03-18 14:33:23 -0400100 const RenderbufferGL *renderbufferGL = GetImplAs<RenderbufferGL>(renderbuffer);
Geoff Lang4ad17092015-03-10 16:47:44 -0400101
Geoff Langcd69f1c2015-03-18 14:33:23 -0400102 functions->framebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER,
103 renderbufferGL->getRenderbufferID());
Geoff Lang4ad17092015-03-10 16:47:44 -0400104 }
105 else
106 {
107 UNREACHABLE();
108 }
109 }
110 else
111 {
112 // Unbind this attachment
113 functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, 0, 0);
114 }
115}
Geoff Langf9a6f082015-01-22 13:32:49 -0500116
Martin Radev61e710b2017-09-05 11:59:52 +0300117bool AreAllLayersActive(const FramebufferAttachment &attachment)
Martin Radevb0761932017-07-25 17:42:25 +0300118{
Martin Radev61e710b2017-09-05 11:59:52 +0300119 int baseViewIndex = attachment.getBaseViewIndex();
120 if (baseViewIndex != 0)
121 {
122 return false;
123 }
124 const ImageIndex &imageIndex = attachment.getTextureImageIndex();
Jamie Madillcc129372018-04-12 09:13:18 -0400125 int numLayers = static_cast<int>(
126 attachment.getTexture()->getDepth(imageIndex.getTarget(), imageIndex.getLevelIndex()));
Martin Radev61e710b2017-09-05 11:59:52 +0300127 return (attachment.getNumViews() == numLayers);
128}
129
130bool RequiresMultiviewClear(const FramebufferState &state, bool scissorTestEnabled)
131{
132 // Get one attachment and check whether all layers are attached.
133 const FramebufferAttachment *attachment = nullptr;
134 bool allTextureArraysAreFullyAttached = true;
135 for (const FramebufferAttachment &colorAttachment : state.getColorAttachments())
136 {
137 if (colorAttachment.isAttached())
138 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700139 if (!colorAttachment.isMultiview())
Martin Radev61e710b2017-09-05 11:59:52 +0300140 {
141 return false;
142 }
143 attachment = &colorAttachment;
144 allTextureArraysAreFullyAttached =
145 allTextureArraysAreFullyAttached && AreAllLayersActive(*attachment);
146 }
147 }
148
149 const FramebufferAttachment *depthAttachment = state.getDepthAttachment();
150 if (depthAttachment)
151 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700152 if (!depthAttachment->isMultiview())
Martin Radev61e710b2017-09-05 11:59:52 +0300153 {
154 return false;
155 }
156 attachment = depthAttachment;
157 allTextureArraysAreFullyAttached =
158 allTextureArraysAreFullyAttached && AreAllLayersActive(*attachment);
159 }
160 const FramebufferAttachment *stencilAttachment = state.getStencilAttachment();
161 if (stencilAttachment)
162 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700163 if (!stencilAttachment->isMultiview())
Martin Radev61e710b2017-09-05 11:59:52 +0300164 {
165 return false;
166 }
167 attachment = stencilAttachment;
168 allTextureArraysAreFullyAttached =
169 allTextureArraysAreFullyAttached && AreAllLayersActive(*attachment);
170 }
171
Martin Radev5e424fa2017-08-09 16:25:36 +0300172 if (attachment == nullptr)
173 {
174 return false;
175 }
Mingyu Hu7d64c482019-03-12 14:27:40 -0700176 if (attachment->isMultiview())
Martin Radev5e424fa2017-08-09 16:25:36 +0300177 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700178 // If all layers of each texture array are active, then there is no need to issue a
179 // special multiview clear.
180 return !allTextureArraysAreFullyAttached;
Martin Radev5e424fa2017-08-09 16:25:36 +0300181 }
182 return false;
Martin Radevb0761932017-07-25 17:42:25 +0300183}
184
Martin Radev878c8b12017-07-28 09:51:04 +0300185} // namespace
186
Geoff Lang61107632018-05-09 11:32:46 -0400187FramebufferGL::FramebufferGL(const gl::FramebufferState &data, GLuint id, bool isDefault)
188 : FramebufferImpl(data),
Martin Radev878c8b12017-07-28 09:51:04 +0300189 mFramebufferID(id),
Geoff Lang61107632018-05-09 11:32:46 -0400190 mIsDefault(isDefault),
Martin Radev878c8b12017-07-28 09:51:04 +0300191 mAppliedEnabledDrawBuffers(1)
Jamie Madillb980c562018-11-27 11:34:27 -0500192{}
Martin Radev878c8b12017-07-28 09:51:04 +0300193
194FramebufferGL::~FramebufferGL()
195{
Geoff Lang61107632018-05-09 11:32:46 -0400196 ASSERT(mFramebufferID == 0);
197}
198
199void FramebufferGL::destroy(const gl::Context *context)
200{
201 StateManagerGL *stateManager = GetStateManagerGL(context);
202 stateManager->deleteFramebuffer(mFramebufferID);
Martin Radev878c8b12017-07-28 09:51:04 +0300203 mFramebufferID = 0;
204}
205
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400206angle::Result FramebufferGL::discard(const gl::Context *context,
207 size_t count,
208 const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -0700209{
Geoff Lang57ce9ea2016-11-24 12:03:14 -0500210 // glInvalidateFramebuffer accepts the same enums as glDiscardFramebufferEXT
Jamie Madill4928b7c2017-06-20 12:57:39 -0400211 return invalidate(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -0700212}
213
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400214angle::Result FramebufferGL::invalidate(const gl::Context *context,
215 size_t count,
216 const GLenum *attachments)
Geoff Langf9a6f082015-01-22 13:32:49 -0500217{
Geoff Lang005a7012017-03-27 13:17:34 -0400218 const GLenum *finalAttachmentsPtr = attachments;
219
220 std::vector<GLenum> modifiedAttachments;
221 if (modifyInvalidateAttachmentsForEmulatedDefaultFBO(count, attachments, &modifiedAttachments))
222 {
223 finalAttachmentsPtr = modifiedAttachments.data();
224 }
225
Geoff Lang61107632018-05-09 11:32:46 -0400226 const FunctionsGL *functions = GetFunctionsGL(context);
227 StateManagerGL *stateManager = GetStateManagerGL(context);
228
Geoff Lang57ce9ea2016-11-24 12:03:14 -0500229 // Since this function is just a hint, only call a native function if it exists.
Geoff Lang61107632018-05-09 11:32:46 -0400230 if (functions->invalidateFramebuffer)
Geoff Lang64a72442015-04-01 14:43:11 -0400231 {
Geoff Lang61107632018-05-09 11:32:46 -0400232 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
233 functions->invalidateFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
234 finalAttachmentsPtr);
Geoff Lang64a72442015-04-01 14:43:11 -0400235 }
Geoff Lang61107632018-05-09 11:32:46 -0400236 else if (functions->discardFramebufferEXT)
Geoff Lang57ce9ea2016-11-24 12:03:14 -0500237 {
Geoff Lang61107632018-05-09 11:32:46 -0400238 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
239 functions->discardFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
240 finalAttachmentsPtr);
Geoff Lang57ce9ea2016-11-24 12:03:14 -0500241 }
Geoff Lang64a72442015-04-01 14:43:11 -0400242
Jamie Madill7c985f52018-11-29 18:16:17 -0500243 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500244}
245
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400246angle::Result FramebufferGL::invalidateSub(const gl::Context *context,
247 size_t count,
248 const GLenum *attachments,
249 const gl::Rectangle &area)
Geoff Langf9a6f082015-01-22 13:32:49 -0500250{
Geoff Lang005a7012017-03-27 13:17:34 -0400251
252 const GLenum *finalAttachmentsPtr = attachments;
253
254 std::vector<GLenum> modifiedAttachments;
255 if (modifyInvalidateAttachmentsForEmulatedDefaultFBO(count, attachments, &modifiedAttachments))
256 {
257 finalAttachmentsPtr = modifiedAttachments.data();
258 }
259
Geoff Lang61107632018-05-09 11:32:46 -0400260 const FunctionsGL *functions = GetFunctionsGL(context);
261 StateManagerGL *stateManager = GetStateManagerGL(context);
262
Jamie Madill231c7f52017-04-26 13:45:37 -0400263 // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is
264 // available.
Geoff Lang61107632018-05-09 11:32:46 -0400265 if (functions->invalidateSubFramebuffer)
Geoff Lang64a72442015-04-01 14:43:11 -0400266 {
Geoff Lang61107632018-05-09 11:32:46 -0400267 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
268 functions->invalidateSubFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
269 finalAttachmentsPtr, area.x, area.y, area.width,
270 area.height);
Geoff Lang64a72442015-04-01 14:43:11 -0400271 }
272
Jamie Madill7c985f52018-11-29 18:16:17 -0500273 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500274}
275
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400276angle::Result FramebufferGL::clear(const gl::Context *context, GLbitfield mask)
Geoff Langf9a6f082015-01-22 13:32:49 -0500277{
Geoff Lang61107632018-05-09 11:32:46 -0400278 const FunctionsGL *functions = GetFunctionsGL(context);
279 StateManagerGL *stateManager = GetStateManagerGL(context);
280
Frank Henigman308d7452017-02-15 22:51:21 -0500281 syncClearState(context, mask);
Geoff Lang61107632018-05-09 11:32:46 -0400282 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
Martin Radevb0761932017-07-25 17:42:25 +0300283
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500284 if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
Martin Radevb0761932017-07-25 17:42:25 +0300285 {
Geoff Lang61107632018-05-09 11:32:46 -0400286 functions->clear(mask);
Martin Radevb0761932017-07-25 17:42:25 +0300287 }
288 else
289 {
Geoff Lang61107632018-05-09 11:32:46 -0400290 ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500291 multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
Geoff Lang61107632018-05-09 11:32:46 -0400292 ClearMultiviewGL::ClearCommandType::Clear, mask,
293 GL_NONE, 0, nullptr, 0.0f, 0);
Martin Radevb0761932017-07-25 17:42:25 +0300294 }
Geoff Lang4ad17092015-03-10 16:47:44 -0400295
Jamie Madill7c985f52018-11-29 18:16:17 -0500296 return angle::Result::Continue;
Geoff Lang4ad17092015-03-10 16:47:44 -0400297}
298
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400299angle::Result FramebufferGL::clearBufferfv(const gl::Context *context,
300 GLenum buffer,
301 GLint drawbuffer,
302 const GLfloat *values)
Geoff Langf9a6f082015-01-22 13:32:49 -0500303{
Geoff Lang61107632018-05-09 11:32:46 -0400304 const FunctionsGL *functions = GetFunctionsGL(context);
305 StateManagerGL *stateManager = GetStateManagerGL(context);
306
Frank Henigman308d7452017-02-15 22:51:21 -0500307 syncClearBufferState(context, buffer, drawbuffer);
Geoff Lang61107632018-05-09 11:32:46 -0400308 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
Martin Radevb0761932017-07-25 17:42:25 +0300309
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500310 if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
Martin Radevb0761932017-07-25 17:42:25 +0300311 {
Geoff Lang61107632018-05-09 11:32:46 -0400312 functions->clearBufferfv(buffer, drawbuffer, values);
Martin Radevb0761932017-07-25 17:42:25 +0300313 }
314 else
315 {
Geoff Lang61107632018-05-09 11:32:46 -0400316 ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500317 multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
Geoff Lang61107632018-05-09 11:32:46 -0400318 ClearMultiviewGL::ClearCommandType::ClearBufferfv,
319 static_cast<GLbitfield>(0u), buffer, drawbuffer,
320 reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
Martin Radevb0761932017-07-25 17:42:25 +0300321 }
Geoff Lang4ad17092015-03-10 16:47:44 -0400322
Jamie Madill7c985f52018-11-29 18:16:17 -0500323 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500324}
325
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400326angle::Result FramebufferGL::clearBufferuiv(const gl::Context *context,
327 GLenum buffer,
328 GLint drawbuffer,
329 const GLuint *values)
Geoff Langf9a6f082015-01-22 13:32:49 -0500330{
Geoff Lang61107632018-05-09 11:32:46 -0400331 const FunctionsGL *functions = GetFunctionsGL(context);
332 StateManagerGL *stateManager = GetStateManagerGL(context);
333
Frank Henigman308d7452017-02-15 22:51:21 -0500334 syncClearBufferState(context, buffer, drawbuffer);
Geoff Lang61107632018-05-09 11:32:46 -0400335 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
Martin Radevb0761932017-07-25 17:42:25 +0300336
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500337 if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
Martin Radevb0761932017-07-25 17:42:25 +0300338 {
Geoff Lang61107632018-05-09 11:32:46 -0400339 functions->clearBufferuiv(buffer, drawbuffer, values);
Martin Radevb0761932017-07-25 17:42:25 +0300340 }
341 else
342 {
Geoff Lang61107632018-05-09 11:32:46 -0400343 ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500344 multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
Geoff Lang61107632018-05-09 11:32:46 -0400345 ClearMultiviewGL::ClearCommandType::ClearBufferuiv,
346 static_cast<GLbitfield>(0u), buffer, drawbuffer,
347 reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
Martin Radevb0761932017-07-25 17:42:25 +0300348 }
Geoff Lang4ad17092015-03-10 16:47:44 -0400349
Jamie Madill7c985f52018-11-29 18:16:17 -0500350 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500351}
352
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400353angle::Result FramebufferGL::clearBufferiv(const gl::Context *context,
354 GLenum buffer,
355 GLint drawbuffer,
356 const GLint *values)
Geoff Langf9a6f082015-01-22 13:32:49 -0500357{
Geoff Lang61107632018-05-09 11:32:46 -0400358 const FunctionsGL *functions = GetFunctionsGL(context);
359 StateManagerGL *stateManager = GetStateManagerGL(context);
360
Frank Henigman308d7452017-02-15 22:51:21 -0500361 syncClearBufferState(context, buffer, drawbuffer);
Geoff Lang61107632018-05-09 11:32:46 -0400362 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
Martin Radevb0761932017-07-25 17:42:25 +0300363
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500364 if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
Martin Radevb0761932017-07-25 17:42:25 +0300365 {
Geoff Lang61107632018-05-09 11:32:46 -0400366 functions->clearBufferiv(buffer, drawbuffer, values);
Martin Radevb0761932017-07-25 17:42:25 +0300367 }
368 else
369 {
Geoff Lang61107632018-05-09 11:32:46 -0400370 ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500371 multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
Geoff Lang61107632018-05-09 11:32:46 -0400372 ClearMultiviewGL::ClearCommandType::ClearBufferiv,
373 static_cast<GLbitfield>(0u), buffer, drawbuffer,
374 reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
Martin Radevb0761932017-07-25 17:42:25 +0300375 }
Geoff Lang4ad17092015-03-10 16:47:44 -0400376
Jamie Madill7c985f52018-11-29 18:16:17 -0500377 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500378}
379
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400380angle::Result FramebufferGL::clearBufferfi(const gl::Context *context,
381 GLenum buffer,
382 GLint drawbuffer,
383 GLfloat depth,
384 GLint stencil)
Geoff Langf9a6f082015-01-22 13:32:49 -0500385{
Geoff Lang61107632018-05-09 11:32:46 -0400386 const FunctionsGL *functions = GetFunctionsGL(context);
387 StateManagerGL *stateManager = GetStateManagerGL(context);
388
Frank Henigman308d7452017-02-15 22:51:21 -0500389 syncClearBufferState(context, buffer, drawbuffer);
Geoff Lang61107632018-05-09 11:32:46 -0400390 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
Martin Radevb0761932017-07-25 17:42:25 +0300391
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500392 if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
Martin Radevb0761932017-07-25 17:42:25 +0300393 {
Geoff Lang61107632018-05-09 11:32:46 -0400394 functions->clearBufferfi(buffer, drawbuffer, depth, stencil);
Martin Radevb0761932017-07-25 17:42:25 +0300395 }
Martin Radev5e424fa2017-08-09 16:25:36 +0300396 else
397 {
Geoff Lang61107632018-05-09 11:32:46 -0400398 ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500399 multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
Geoff Lang61107632018-05-09 11:32:46 -0400400 ClearMultiviewGL::ClearCommandType::ClearBufferfi,
401 static_cast<GLbitfield>(0u), buffer, drawbuffer,
402 nullptr, depth, stencil);
Martin Radev5e424fa2017-08-09 16:25:36 +0300403 }
Geoff Lang4ad17092015-03-10 16:47:44 -0400404
Jamie Madill7c985f52018-11-29 18:16:17 -0500405 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500406}
407
Jamie Madill4928b7c2017-06-20 12:57:39 -0400408GLenum FramebufferGL::getImplementationColorReadFormat(const gl::Context *context) const
Geoff Langf9a6f082015-01-22 13:32:49 -0500409{
Jamie Madilla3944d42016-07-22 22:13:26 -0400410 const auto *readAttachment = mState.getReadAttachment();
411 const Format &format = readAttachment->getFormat();
Geoff Langf607c602016-09-21 11:46:48 -0400412 return format.info->getReadPixelsFormat();
Geoff Langf9a6f082015-01-22 13:32:49 -0500413}
414
Jamie Madill4928b7c2017-06-20 12:57:39 -0400415GLenum FramebufferGL::getImplementationColorReadType(const gl::Context *context) const
Geoff Langf9a6f082015-01-22 13:32:49 -0500416{
Jamie Madilla3944d42016-07-22 22:13:26 -0400417 const auto *readAttachment = mState.getReadAttachment();
418 const Format &format = readAttachment->getFormat();
Geoff Langc71ea662017-09-26 17:06:02 -0400419 return format.info->getReadPixelsType(context->getClientVersion());
Geoff Langf9a6f082015-01-22 13:32:49 -0500420}
421
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400422angle::Result FramebufferGL::readPixels(const gl::Context *context,
423 const gl::Rectangle &area,
424 GLenum format,
425 GLenum type,
426 void *pixels)
Geoff Langf9a6f082015-01-22 13:32:49 -0500427{
Jamie Madill4e71b2b2019-07-08 13:23:38 -0400428 ContextGL *contextGL = GetImplAs<ContextGL>(context);
429 const FunctionsGL *functions = GetFunctionsGL(context);
430 StateManagerGL *stateManager = GetStateManagerGL(context);
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -0400431 const angle::FeaturesGL &features = GetFeaturesGL(context);
Geoff Lang61107632018-05-09 11:32:46 -0400432
Frank Henigmanfa36c332017-06-09 18:44:45 -0400433 // Clip read area to framebuffer.
434 const gl::Extents fbSize = getState().getReadAttachment()->getSize();
435 const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400436 gl::Rectangle clippedArea;
437 if (!ClipRectangle(area, fbRect, &clippedArea))
Frank Henigmanfa36c332017-06-09 18:44:45 -0400438 {
439 // nothing to read
Jamie Madill7c985f52018-11-29 18:16:17 -0500440 return angle::Result::Continue;
Frank Henigmanfa36c332017-06-09 18:44:45 -0400441 }
442
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500443 PixelPackState packState = context->getState().getPackState();
Corentin Wallez336129f2017-10-17 15:55:40 -0400444 const gl::Buffer *packBuffer =
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500445 context->getState().getTargetBuffer(gl::BufferBinding::PixelPack);
Jamie Madill87de3622015-03-16 10:41:44 -0400446
Geoff Langf607c602016-09-21 11:46:48 -0400447 nativegl::ReadPixelsFormat readPixelsFormat =
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -0400448 nativegl::GetReadPixelsFormat(functions, features, format, type);
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400449 GLenum readFormat = readPixelsFormat.format;
450 GLenum readType = readPixelsFormat.type;
Geoff Lang4ad17092015-03-10 16:47:44 -0400451
Geoff Lang61107632018-05-09 11:32:46 -0400452 stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID);
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400453
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -0400454 bool useOverlappingRowsWorkaround = features.packOverlappingRowsSeparatelyPackBuffer.enabled &&
455 packBuffer && packState.rowLength != 0 &&
456 packState.rowLength < clippedArea.width;
Frank Henigmanfa36c332017-06-09 18:44:45 -0400457
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400458 GLubyte *outPtr = static_cast<GLubyte *>(pixels);
459 int leftClip = clippedArea.x - area.x;
460 int topClip = clippedArea.y - area.y;
Frank Henigmanfa36c332017-06-09 18:44:45 -0400461 if (leftClip || topClip)
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400462 {
Frank Henigmanfa36c332017-06-09 18:44:45 -0400463 // Adjust destination to match portion clipped off left and/or top.
464 const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(readFormat, readType);
465
466 GLuint rowBytes = 0;
Jamie Madille39e8f42018-10-05 08:17:38 -0400467 ANGLE_CHECK_GL_MATH(contextGL,
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400468 glFormat.computeRowPitch(readType, area.width, packState.alignment,
Jamie Madille39e8f42018-10-05 08:17:38 -0400469 packState.rowLength, &rowBytes));
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400470 outPtr += leftClip * glFormat.pixelBytes + topClip * rowBytes;
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400471 }
472
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400473 if (packState.rowLength == 0 && clippedArea.width != area.width)
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400474 {
Frank Henigmanfa36c332017-06-09 18:44:45 -0400475 // No rowLength was specified so it will derive from read width, but clipping changed the
476 // read width. Use the original width so we fill the user's buffer as they intended.
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400477 packState.rowLength = area.width;
Frank Henigmanfa36c332017-06-09 18:44:45 -0400478 }
Corentin Wallez886de362016-09-27 10:49:35 -0400479
Frank Henigmanfa36c332017-06-09 18:44:45 -0400480 // We want to use rowLength, but that might not be supported.
481 bool cannotSetDesiredRowLength =
482 packState.rowLength && !GetImplAs<ContextGL>(context)->getNativeExtensions().packSubimage;
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400483
Frank Henigmanfa36c332017-06-09 18:44:45 -0400484 if (cannotSetDesiredRowLength || useOverlappingRowsWorkaround)
485 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400486 return readPixelsRowByRow(context, clippedArea, readFormat, readType, packState, outPtr);
Frank Henigmanfa36c332017-06-09 18:44:45 -0400487 }
Jamie Madill13951342018-09-30 15:24:28 -0400488
489 bool useLastRowPaddingWorkaround = false;
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -0400490 if (features.packLastRowSeparatelyForPaddingInclusion.enabled)
Frank Henigmanfa36c332017-06-09 18:44:45 -0400491 {
Jamie Madille39e8f42018-10-05 08:17:38 -0400492 ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400493 contextGL, gl::Extents(clippedArea.width, clippedArea.height, 1), packState, packBuffer,
494 readFormat, readType, false, outPtr, &useLastRowPaddingWorkaround));
Corentin Wallez9a8d3662016-09-22 12:18:29 -0400495 }
496
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400497 return readPixelsAllAtOnce(context, clippedArea, readFormat, readType, packState, outPtr,
Jamie Madill13951342018-09-30 15:24:28 -0400498 useLastRowPaddingWorkaround);
Geoff Langf9a6f082015-01-22 13:32:49 -0500499}
500
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400501angle::Result FramebufferGL::blit(const gl::Context *context,
502 const gl::Rectangle &sourceArea,
503 const gl::Rectangle &destArea,
504 GLbitfield mask,
505 GLenum filter)
Geoff Langf9a6f082015-01-22 13:32:49 -0500506{
Geoff Lang61107632018-05-09 11:32:46 -0400507 const FunctionsGL *functions = GetFunctionsGL(context);
508 StateManagerGL *stateManager = GetStateManagerGL(context);
Jonah Ryan-Davis7151fe52019-07-17 15:15:27 -0400509 const angle::FeaturesGL &features = GetFeaturesGL(context);
Geoff Lang61107632018-05-09 11:32:46 -0400510
Jamie Madillc3dc5d42018-12-30 12:12:04 -0500511 const Framebuffer *sourceFramebuffer = context->getState().getReadFramebuffer();
512 const Framebuffer *destFramebuffer = context->getState().getDrawFramebuffer();
Geoff Lang4ad17092015-03-10 16:47:44 -0400513
Jamie Madill4e71b2b2019-07-08 13:23:38 -0400514 const FramebufferAttachment *colorReadAttachment = sourceFramebuffer->getReadColorAttachment();
Corentin Wallez4596a762016-12-20 14:50:18 -0500515
516 GLsizei readAttachmentSamples = 0;
517 if (colorReadAttachment != nullptr)
518 {
519 readAttachmentSamples = colorReadAttachment->getSamples();
520 }
Corentin Wallez6898b352016-11-10 11:41:15 -0500521
Corentin Wallez26a717b2016-09-27 08:45:42 -0700522 bool needManualColorBlit = false;
523
Corentin Wallez6898b352016-11-10 11:41:15 -0500524 // TODO(cwallez) when the filter is LINEAR and both source and destination are SRGB, we
525 // could avoid doing a manual blit.
526
527 // Prior to OpenGL 4.4 BlitFramebuffer (section 18.3.1 of GL 4.3 core profile) reads:
528 // When values are taken from the read buffer, no linearization is performed, even
529 // if the format of the buffer is SRGB.
530 // Starting from OpenGL 4.4 (section 18.3.1) it reads:
531 // When values are taken from the read buffer, if FRAMEBUFFER_SRGB is enabled and the
532 // value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment
533 // corresponding to the read buffer is SRGB, the red, green, and blue components are
534 // converted from the non-linear sRGB color space according [...].
Corentin Wallez26a717b2016-09-27 08:45:42 -0700535 {
Jamie Madill231c7f52017-04-26 13:45:37 -0400536 bool sourceSRGB =
537 colorReadAttachment != nullptr && colorReadAttachment->getColorEncoding() == GL_SRGB;
Corentin Wallez6898b352016-11-10 11:41:15 -0500538 needManualColorBlit =
Geoff Lang61107632018-05-09 11:32:46 -0400539 needManualColorBlit || (sourceSRGB && functions->isAtMostGL(gl::Version(4, 3)));
Corentin Wallez6898b352016-11-10 11:41:15 -0500540 }
Corentin Wallez26a717b2016-09-27 08:45:42 -0700541
Corentin Wallez6898b352016-11-10 11:41:15 -0500542 // Prior to OpenGL 4.2 BlitFramebuffer (section 4.3.2 of GL 4.1 core profile) reads:
543 // Blit operations bypass the fragment pipeline. The only fragment operations which
544 // affect a blit are the pixel ownership test and scissor test.
545 // Starting from OpenGL 4.2 (section 4.3.2) it reads:
546 // When values are written to the draw buffers, blit operations bypass the fragment
547 // pipeline. The only fragment operations which affect a blit are the pixel ownership
548 // test, the scissor test and sRGB conversion.
549 if (!needManualColorBlit)
550 {
551 bool destSRGB = false;
552 for (size_t i = 0; i < destFramebuffer->getDrawbufferStateCount(); ++i)
Corentin Wallez26a717b2016-09-27 08:45:42 -0700553 {
Corentin Wallez6898b352016-11-10 11:41:15 -0500554 const FramebufferAttachment *attachment = destFramebuffer->getDrawBuffer(i);
555 if (attachment && attachment->getColorEncoding() == GL_SRGB)
Corentin Wallez26a717b2016-09-27 08:45:42 -0700556 {
Corentin Wallez6898b352016-11-10 11:41:15 -0500557 destSRGB = true;
558 break;
Corentin Wallez26a717b2016-09-27 08:45:42 -0700559 }
Corentin Wallez26a717b2016-09-27 08:45:42 -0700560 }
Corentin Wallez6898b352016-11-10 11:41:15 -0500561
562 needManualColorBlit =
Geoff Lang61107632018-05-09 11:32:46 -0400563 needManualColorBlit || (destSRGB && functions->isAtMostGL(gl::Version(4, 1)));
Corentin Wallez26a717b2016-09-27 08:45:42 -0700564 }
565
566 // Enable FRAMEBUFFER_SRGB if needed
Geoff Lang61107632018-05-09 11:32:46 -0400567 stateManager->setFramebufferSRGBEnabledForFramebuffer(context, true, this);
Corentin Wallez26a717b2016-09-27 08:45:42 -0700568
569 GLenum blitMask = mask;
Corentin Wallez6898b352016-11-10 11:41:15 -0500570 if (needManualColorBlit && (mask & GL_COLOR_BUFFER_BIT) && readAttachmentSamples <= 1)
Corentin Wallez26a717b2016-09-27 08:45:42 -0700571 {
Geoff Lang61107632018-05-09 11:32:46 -0400572 BlitGL *blitter = GetBlitGL(context);
Jamie Madille39e8f42018-10-05 08:17:38 -0400573 ANGLE_TRY(blitter->blitColorBufferWithShader(context, sourceFramebuffer, destFramebuffer,
574 sourceArea, destArea, filter));
Corentin Wallez26a717b2016-09-27 08:45:42 -0700575 blitMask &= ~GL_COLOR_BUFFER_BIT;
576 }
577
578 if (blitMask == 0)
579 {
Jamie Madill7c985f52018-11-29 18:16:17 -0500580 return angle::Result::Continue;
Corentin Wallez26a717b2016-09-27 08:45:42 -0700581 }
582
583 const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer);
Geoff Lang61107632018-05-09 11:32:46 -0400584 stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
585 stateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID);
Geoff Lang4ad17092015-03-10 16:47:44 -0400586
Jonah Ryan-Davis7151fe52019-07-17 15:15:27 -0400587 if (features.adjustSrcDstRegionBlitFramebuffer.enabled)
588 {
589 gl::Rectangle newSourceArea;
590 gl::Rectangle newDestArea;
591 // This workaround is taken from chromium: http://crbug.com/830046
592 if (adjustSrcDstRegion(context, sourceArea, destArea, &newSourceArea, &newDestArea) ==
593 angle::Result::Continue)
594 {
595 functions->blitFramebuffer(newSourceArea.x, newSourceArea.y, newSourceArea.x1(),
596 newSourceArea.y1(), newDestArea.x, newDestArea.y,
597 newDestArea.x1(), newDestArea.y1(), blitMask, filter);
598 }
599 }
600 else
601 {
602 functions->blitFramebuffer(sourceArea.x, sourceArea.y, sourceArea.x1(), sourceArea.y1(),
603 destArea.x, destArea.y, destArea.x1(), destArea.y1(), blitMask,
604 filter);
605 }
606
607 return angle::Result::Continue;
608}
609
610angle::Result FramebufferGL::adjustSrcDstRegion(const gl::Context *context,
611 const gl::Rectangle &sourceArea,
612 const gl::Rectangle &destArea,
613 gl::Rectangle *newSourceArea,
614 gl::Rectangle *newDestArea)
615{
616 const Framebuffer *sourceFramebuffer = context->getState().getReadFramebuffer();
617 const Framebuffer *destFramebuffer = context->getState().getDrawFramebuffer();
618
619 gl::Extents readSize = sourceFramebuffer->getExtents();
620 gl::Extents drawSize = destFramebuffer->getExtents();
621
622 CheckedNumeric<GLint> sourceWidthTemp = sourceArea.x1();
623 sourceWidthTemp -= sourceArea.x;
624 CheckedNumeric<GLint> sourceHeightTemp = sourceArea.y1();
625 sourceHeightTemp -= sourceArea.y;
626 CheckedNumeric<GLint> destWidthTemp = destArea.x1();
627 destWidthTemp -= destArea.x;
628 CheckedNumeric<GLint> destHeightTemp = destArea.y1();
629 destHeightTemp -= destArea.y;
630
631 GLint sourceX = sourceArea.x1() > sourceArea.x ? sourceArea.x : sourceArea.x1();
632 GLint sourceY = sourceArea.y1() > sourceArea.y ? sourceArea.y : sourceArea.y1();
633 GLuint sourceWidth = angle::base::checked_cast<GLuint>(sourceWidthTemp.Abs().ValueOrDefault(0));
634 GLuint sourceHeight =
635 angle::base::checked_cast<GLuint>(sourceHeightTemp.Abs().ValueOrDefault(0));
636
637 GLint destX = destArea.x1() > destArea.x ? destArea.x : destArea.x1();
638 GLint destY = destArea.y1() > destArea.y ? destArea.y : destArea.y1();
639 GLuint destWidth = angle::base::checked_cast<GLuint>(destWidthTemp.Abs().ValueOrDefault(0));
640 GLuint destHeight = angle::base::checked_cast<GLuint>(destHeightTemp.Abs().ValueOrDefault(0));
641
642 if (destWidth == 0 || sourceWidth == 0 || destHeight == 0 || sourceHeight == 0)
643 {
644 return angle::Result::Stop;
645 }
646
647 gl::Rectangle sourceBounds(0, 0, readSize.width, readSize.height);
648 gl::Rectangle sourceRegion(sourceX, sourceY, sourceWidth, sourceHeight);
649
650 gl::Rectangle destBounds(0, 0, drawSize.width, drawSize.height);
651 gl::Rectangle destRegion(destX, destY, destWidth, destHeight);
652
653 if (!ClipRectangle(destBounds, destRegion, nullptr))
654 {
655 return angle::Result::Stop;
656 }
657
658 bool xFlipped = ((sourceArea.x1() > sourceArea.x) && (destArea.x1() < destArea.x)) ||
659 ((sourceArea.x1() < sourceArea.x) && (destArea.x1() > destArea.x));
660 bool yFlipped = ((sourceArea.y1() > sourceArea.y) && (destArea.y1() < destArea.y)) ||
661 ((sourceArea.y1() < sourceArea.y) && (destArea.y1() > destArea.y));
662
663 if (!destBounds.encloses(destRegion))
664 {
665 // destRegion is not within destBounds. We want to adjust it to a
666 // reasonable size. This is done by halving the destRegion until it is at
667 // most twice the size of the framebuffer. We cut it in half instead
668 // of arbitrarily shrinking it to fit so that we don't end up with
669 // non-power-of-two scale factors which could mess up pixel interpolation.
670 // Naively clipping the dst rect and then proportionally sizing the
671 // src rect yields incorrect results.
672
673 GLuint destXHalvings = 0;
674 GLuint destYHalvings = 0;
675 GLint destOriginX = destX;
676 GLint destOriginY = destY;
677
678 GLint destClippedWidth = destRegion.width;
679 while (destClippedWidth > 2 * destBounds.width)
680 {
681 destClippedWidth = destClippedWidth / 2;
682 destXHalvings++;
683 }
684
685 GLint destClippedHeight = destRegion.height;
686 while (destClippedHeight > 2 * destBounds.height)
687 {
688 destClippedHeight = destClippedHeight / 2;
689 destYHalvings++;
690 }
691
692 // Before this block, we check that the two rectangles intersect.
693 // Now, compute the location of a new region origin such that we use the
694 // scaled dimensions but the new region has the same intersection as the
695 // original region.
696
697 GLint left = destRegion.x0();
698 GLint right = destRegion.x1();
699 GLint top = destRegion.y0();
700 GLint bottom = destRegion.y1();
701
702 GLint extraXOffset = 0;
703 if (left >= 0 && left < destBounds.width)
704 {
705 // Left edge is in-bounds
706 destOriginX = destX;
707 }
708 else if (right > 0 && right <= destBounds.width)
709 {
710 // Right edge is in-bounds
711 destOriginX = right - destClippedWidth;
712 }
713 else
714 {
715 // Region completely spans bounds
716 extraXOffset = (destRegion.width - destClippedWidth) / 2;
717 destOriginX = destX + extraXOffset;
718 }
719
720 GLint extraYOffset = 0;
721 if (top >= 0 && top < destBounds.height)
722 {
723 // Top edge is in-bounds
724 destOriginY = destY;
725 }
726 else if (bottom > 0 && bottom <= destBounds.height)
727 {
728 // Bottom edge is in-bounds
729 destOriginY = bottom - destClippedHeight;
730 }
731 else
732 {
733 // Region completely spans bounds
734 extraYOffset = (destRegion.height - destClippedHeight) / 2;
735 destOriginY = destY + extraYOffset;
736 }
737
738 destRegion = gl::Rectangle(destOriginX, destOriginY, destClippedWidth, destClippedHeight);
739
740 // Offsets from the bottom left corner of the original region to
741 // the bottom left corner of the clipped region.
742 // This value (after it is scaled) is the respective offset we will apply
743 // to the src origin.
744
745 CheckedNumeric<GLuint> checkedXOffset(destRegion.x - destX - extraXOffset / 2);
746 CheckedNumeric<GLuint> checkedYOffset(destRegion.y - destY - extraYOffset / 2);
747
748 // if X/Y is reversed, use the top/right out-of-bounds region to compute
749 // the origin offset instead of the left/bottom out-of-bounds region
750 if (xFlipped)
751 {
752 checkedXOffset = (destX + destWidth - destRegion.x1() + extraXOffset / 2);
753 }
754 if (yFlipped)
755 {
756 checkedYOffset = (destY + destHeight - destRegion.y1() + extraYOffset / 2);
757 }
758
759 // These offsets should never overflow
760 GLuint xOffset, yOffset;
761 if (!checkedXOffset.AssignIfValid(&xOffset) || !checkedYOffset.AssignIfValid(&yOffset))
762 {
763 UNREACHABLE();
764 return angle::Result::Stop;
765 }
766
767 // Adjust the src region by the same factor
768 sourceRegion = gl::Rectangle(
769 sourceX + (xOffset >> destXHalvings), sourceY + (yOffset >> destYHalvings),
770 sourceRegion.width >> destXHalvings, sourceRegion.height >> destYHalvings);
771
772 // if the src was scaled to 0, set it to 1 so the src is non-empty
773 if (sourceRegion.width == 0)
774 {
775 sourceRegion.width = 1;
776 }
777 if (sourceRegion.height == 0)
778 {
779 sourceRegion.height = 1;
780 }
781 }
782
783 if (!sourceBounds.encloses(sourceRegion))
784 {
785 // sourceRegion is not within sourceBounds. We want to adjust it to a
786 // reasonable size. This is done by halving the sourceRegion until it is at
787 // most twice the size of the framebuffer. We cut it in half instead
788 // of arbitrarily shrinking it to fit so that we don't end up with
789 // non-power-of-two scale factors which could mess up pixel interpolation.
790 // Naively clipping the source rect and then proportionally sizing the
791 // dest rect yields incorrect results.
792
793 GLuint sourceXHalvings = 0;
794 GLuint sourceYHalvings = 0;
795 GLint sourceOriginX = sourceX;
796 GLint sourceOriginY = sourceY;
797
798 GLint sourceClippedWidth = sourceRegion.width;
799 while (sourceClippedWidth > 2 * sourceBounds.width)
800 {
801 sourceClippedWidth = sourceClippedWidth / 2;
802 sourceXHalvings++;
803 }
804
805 GLint sourceClippedHeight = sourceRegion.height;
806 while (sourceClippedHeight > 2 * sourceBounds.height)
807 {
808 sourceClippedHeight = sourceClippedHeight / 2;
809 sourceYHalvings++;
810 }
811
812 // Before this block, we check that the two rectangles intersect.
813 // Now, compute the location of a new region origin such that we use the
814 // scaled dimensions but the new region has the same intersection as the
815 // original region.
816
817 GLint left = sourceRegion.x0();
818 GLint right = sourceRegion.x1();
819 GLint top = sourceRegion.y0();
820 GLint bottom = sourceRegion.y1();
821
822 GLint extraXOffset = 0;
823 if (left >= 0 && left < sourceBounds.width)
824 {
825 // Left edge is in-bounds
826 sourceOriginX = sourceX;
827 }
828 else if (right > 0 && right <= sourceBounds.width)
829 {
830 // Right edge is in-bounds
831 sourceOriginX = right - sourceClippedWidth;
832 }
833 else
834 {
835 // Region completely spans bounds
836 extraXOffset = (sourceRegion.width - sourceClippedWidth) / 2;
837 sourceOriginX = sourceX + extraXOffset;
838 }
839
840 GLint extraYOffset = 0;
841 if (top >= 0 && top < sourceBounds.height)
842 {
843 // Top edge is in-bounds
844 sourceOriginY = sourceY;
845 }
846 else if (bottom > 0 && bottom <= sourceBounds.height)
847 {
848 // Bottom edge is in-bounds
849 sourceOriginY = bottom - sourceClippedHeight;
850 }
851 else
852 {
853 // Region completely spans bounds
854 extraYOffset = (sourceRegion.height - sourceClippedHeight) / 2;
855 sourceOriginY = sourceY + extraYOffset;
856 }
857
858 sourceRegion =
859 gl::Rectangle(sourceOriginX, sourceOriginY, sourceClippedWidth, sourceClippedHeight);
860
861 // Offsets from the bottom left corner of the original region to
862 // the bottom left corner of the clipped region.
863 // This value (after it is scaled) is the respective offset we will apply
864 // to the dest origin.
865
866 CheckedNumeric<GLuint> checkedXOffset(sourceRegion.x - sourceX - extraXOffset / 2);
867 CheckedNumeric<GLuint> checkedYOffset(sourceRegion.y - sourceY - extraYOffset / 2);
868
869 // if X/Y is reversed, use the top/right out-of-bounds region to compute
870 // the origin offset instead of the left/bottom out-of-bounds region
871 if (xFlipped)
872 {
873 checkedXOffset = (sourceX + sourceWidth - sourceRegion.x1() + extraXOffset / 2);
874 }
875 if (yFlipped)
876 {
877 checkedYOffset = (sourceY + sourceHeight - sourceRegion.y1() + extraYOffset / 2);
878 }
879
880 // These offsets should never overflow
881 GLuint xOffset, yOffset;
882 if (!checkedXOffset.AssignIfValid(&xOffset) || !checkedYOffset.AssignIfValid(&yOffset))
883 {
884 UNREACHABLE();
885 return angle::Result::Stop;
886 }
887
888 // Adjust the dest region by the same factor
889 destRegion = gl::Rectangle(
890 destX + (xOffset >> sourceXHalvings), destY + (yOffset >> sourceYHalvings),
891 destRegion.width >> sourceXHalvings, destRegion.height >> sourceYHalvings);
892 }
893 // Set the src and dst endpoints. If they were previously flipped,
894 // set them as flipped.
895 *newSourceArea = gl::Rectangle(
896 sourceArea.x0() < sourceArea.x1() ? sourceRegion.x0() : sourceRegion.x1(),
897 sourceArea.y0() < sourceArea.y1() ? sourceRegion.y0() : sourceRegion.y1(),
898 sourceArea.x0() < sourceArea.x1() ? sourceRegion.width : -sourceRegion.width,
899 sourceArea.y0() < sourceArea.y1() ? sourceRegion.height : -sourceRegion.height);
900
901 *newDestArea =
902 gl::Rectangle(destArea.x0() < destArea.x1() ? destRegion.x0() : destRegion.x1(),
903 destArea.y0() < destArea.y1() ? destRegion.y0() : destRegion.y1(),
904 destArea.x0() < destArea.x1() ? destRegion.width : -destRegion.width,
905 destArea.y0() < destArea.y1() ? destRegion.height : -destRegion.height);
Geoff Lang4ad17092015-03-10 16:47:44 -0400906
Jamie Madill7c985f52018-11-29 18:16:17 -0500907 return angle::Result::Continue;
Geoff Langf9a6f082015-01-22 13:32:49 -0500908}
909
Jamie Madill64b7c4f2018-10-19 11:38:04 -0400910angle::Result FramebufferGL::getSamplePosition(const gl::Context *context,
911 size_t index,
912 GLfloat *xy) const
JiangYizhoubddc46b2016-12-09 09:50:51 +0800913{
Geoff Lang61107632018-05-09 11:32:46 -0400914 const FunctionsGL *functions = GetFunctionsGL(context);
915 StateManagerGL *stateManager = GetStateManagerGL(context);
916
917 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
918 functions->getMultisamplefv(GL_SAMPLE_POSITION, static_cast<GLuint>(index), xy);
Jamie Madill7c985f52018-11-29 18:16:17 -0500919 return angle::Result::Continue;
JiangYizhoubddc46b2016-12-09 09:50:51 +0800920}
921
Jamie Madill67220092019-05-20 11:12:53 -0400922bool FramebufferGL::shouldSyncStateBeforeCheckStatus() const
923{
924 return true;
925}
926
Kenneth Russellce8602a2017-10-03 18:23:08 -0700927bool FramebufferGL::checkStatus(const gl::Context *context) const
Geoff Langf9a6f082015-01-22 13:32:49 -0500928{
Geoff Lang61107632018-05-09 11:32:46 -0400929 const FunctionsGL *functions = GetFunctionsGL(context);
930 StateManagerGL *stateManager = GetStateManagerGL(context);
931
932 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
933 GLenum status = functions->checkFramebufferStatus(GL_FRAMEBUFFER);
Jamie Madillcc86d642015-11-24 13:00:07 -0500934 if (status != GL_FRAMEBUFFER_COMPLETE)
935 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500936 WARN() << "GL framebuffer returned incomplete.";
Jamie Madillcc86d642015-11-24 13:00:07 -0500937 }
938 return (status == GL_FRAMEBUFFER_COMPLETE);
Geoff Lang4ad17092015-03-10 16:47:44 -0400939}
940
Jamie Madill6f755b22018-10-09 12:48:54 -0400941angle::Result FramebufferGL::syncState(const gl::Context *context,
942 const gl::Framebuffer::DirtyBits &dirtyBits)
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500943{
944 // Don't need to sync state for the default FBO.
945 if (mIsDefault)
946 {
Jamie Madill7c985f52018-11-29 18:16:17 -0500947 return angle::Result::Continue;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500948 }
949
Geoff Lang61107632018-05-09 11:32:46 -0400950 const FunctionsGL *functions = GetFunctionsGL(context);
951 StateManagerGL *stateManager = GetStateManagerGL(context);
952
953 stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500954
Martin Radev7c2e6a92017-08-28 11:13:16 +0300955 // A pointer to one of the attachments for which the texture or the render buffer is not zero.
956 const FramebufferAttachment *attachment = nullptr;
Martin Radev878c8b12017-07-28 09:51:04 +0300957
Jamie Madill6de51852017-04-12 09:53:01 -0400958 for (auto dirtyBit : dirtyBits)
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500959 {
960 switch (dirtyBit)
961 {
962 case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
Martin Radev7c2e6a92017-08-28 11:13:16 +0300963 {
964 const FramebufferAttachment *newAttachment = mState.getDepthAttachment();
Geoff Lang61107632018-05-09 11:32:46 -0400965 BindFramebufferAttachment(functions, GL_DEPTH_ATTACHMENT, newAttachment);
Martin Radev7c2e6a92017-08-28 11:13:16 +0300966 if (newAttachment)
967 {
968 attachment = newAttachment;
969 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500970 break;
Martin Radev7c2e6a92017-08-28 11:13:16 +0300971 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500972 case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
Martin Radev7c2e6a92017-08-28 11:13:16 +0300973 {
974 const FramebufferAttachment *newAttachment = mState.getStencilAttachment();
Geoff Lang61107632018-05-09 11:32:46 -0400975 BindFramebufferAttachment(functions, GL_STENCIL_ATTACHMENT, newAttachment);
Martin Radev7c2e6a92017-08-28 11:13:16 +0300976 if (newAttachment)
977 {
978 attachment = newAttachment;
979 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500980 break;
Martin Radev7c2e6a92017-08-28 11:13:16 +0300981 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500982 case Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
983 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400984 const auto &drawBuffers = mState.getDrawBufferStates();
Geoff Lang61107632018-05-09 11:32:46 -0400985 functions->drawBuffers(static_cast<GLsizei>(drawBuffers.size()),
986 drawBuffers.data());
Corentin Walleze7557742017-06-01 13:09:57 -0400987 mAppliedEnabledDrawBuffers = mState.getEnabledDrawBuffers();
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500988 break;
989 }
990 case Framebuffer::DIRTY_BIT_READ_BUFFER:
Geoff Lang61107632018-05-09 11:32:46 -0400991 functions->readBuffer(mState.getReadBufferState());
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500992 break;
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800993 case Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
Geoff Lang61107632018-05-09 11:32:46 -0400994 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
995 mState.getDefaultWidth());
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800996 break;
997 case Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
Geoff Lang61107632018-05-09 11:32:46 -0400998 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
999 mState.getDefaultHeight());
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001000 break;
1001 case Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
Geoff Lang61107632018-05-09 11:32:46 -04001002 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES,
1003 mState.getDefaultSamples());
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001004 break;
1005 case Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
Geoff Lang61107632018-05-09 11:32:46 -04001006 functions->framebufferParameteri(
Geoff Lang92019432017-11-20 13:09:34 -05001007 GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS,
1008 gl::ConvertToGLBoolean(mState.getDefaultFixedSampleLocations()));
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001009 break;
Jiawei Shaob1e91382018-05-17 14:33:55 +08001010 case Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
1011 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT,
1012 mState.getDefaultLayers());
1013 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001014 default:
1015 {
Jamie Madill67220092019-05-20 11:12:53 -04001016 static_assert(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
1017 if (dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
Martin Radev7c2e6a92017-08-28 11:13:16 +03001018 {
Jamie Madill67220092019-05-20 11:12:53 -04001019 size_t index =
1020 static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
1021 const FramebufferAttachment *newAttachment = mState.getColorAttachment(index);
1022 BindFramebufferAttachment(functions,
1023 static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
1024 newAttachment);
1025 if (newAttachment)
1026 {
1027 attachment = newAttachment;
1028 }
Martin Radev7c2e6a92017-08-28 11:13:16 +03001029 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001030 break;
1031 }
1032 }
1033 }
Martin Radev878c8b12017-07-28 09:51:04 +03001034
Jamie Madillc3dc5d42018-12-30 12:12:04 -05001035 if (attachment && mState.id() == context->getState().getDrawFramebuffer()->id())
Martin Radev878c8b12017-07-28 09:51:04 +03001036 {
Jamie Madillc3dc5d42018-12-30 12:12:04 -05001037 stateManager->updateMultiviewBaseViewLayerIndexUniform(context->getState().getProgram(),
Geoff Lang61107632018-05-09 11:32:46 -04001038 getState());
Martin Radev878c8b12017-07-28 09:51:04 +03001039 }
Jamie Madill19fa1c62018-03-08 09:47:21 -05001040
Jamie Madill7c985f52018-11-29 18:16:17 -05001041 return angle::Result::Continue;
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001042}
1043
Geoff Lang4ad17092015-03-10 16:47:44 -04001044GLuint FramebufferGL::getFramebufferID() const
1045{
1046 return mFramebufferID;
Geoff Langf9a6f082015-01-22 13:32:49 -05001047}
1048
Geoff Lang1d2c41d2016-10-19 16:14:46 -07001049bool FramebufferGL::isDefault() const
Geoff Langafd7f0a2015-09-09 15:33:31 -04001050{
Geoff Lang1d2c41d2016-10-19 16:14:46 -07001051 return mIsDefault;
Geoff Langafd7f0a2015-09-09 15:33:31 -04001052}
1053
Jamie Madillc564c072017-06-01 12:45:42 -04001054void FramebufferGL::syncClearState(const gl::Context *context, GLbitfield mask)
Geoff Langafd7f0a2015-09-09 15:33:31 -04001055{
Geoff Lang61107632018-05-09 11:32:46 -04001056 const FunctionsGL *functions = GetFunctionsGL(context);
1057
1058 if (functions->standard == STANDARD_GL_DESKTOP)
Geoff Langafd7f0a2015-09-09 15:33:31 -04001059 {
Jamie Madill4e71b2b2019-07-08 13:23:38 -04001060 StateManagerGL *stateManager = GetStateManagerGL(context);
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -04001061 const angle::FeaturesGL &features = GetFeaturesGL(context);
Geoff Lang61107632018-05-09 11:32:46 -04001062
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -04001063 if (features.doesSRGBClearsOnLinearFramebufferAttachments.enabled &&
Frank Henigmana3d333c2016-03-22 22:09:14 -04001064 (mask & GL_COLOR_BUFFER_BIT) != 0 && !mIsDefault)
Geoff Langafd7f0a2015-09-09 15:33:31 -04001065 {
Corentin Wallez26a717b2016-09-27 08:45:42 -07001066 bool hasSRGBAttachment = false;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001067 for (const auto &attachment : mState.getColorAttachments())
Geoff Langafd7f0a2015-09-09 15:33:31 -04001068 {
Frank Henigmana3d333c2016-03-22 22:09:14 -04001069 if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB)
1070 {
Corentin Wallez26a717b2016-09-27 08:45:42 -07001071 hasSRGBAttachment = true;
Frank Henigmana3d333c2016-03-22 22:09:14 -04001072 break;
1073 }
Geoff Langafd7f0a2015-09-09 15:33:31 -04001074 }
Geoff Langafd7f0a2015-09-09 15:33:31 -04001075
Geoff Lang61107632018-05-09 11:32:46 -04001076 stateManager->setFramebufferSRGBEnabled(context, hasSRGBAttachment);
Frank Henigmana3d333c2016-03-22 22:09:14 -04001077 }
1078 else
1079 {
Geoff Lang61107632018-05-09 11:32:46 -04001080 stateManager->setFramebufferSRGBEnabled(context, !mIsDefault);
Frank Henigmana3d333c2016-03-22 22:09:14 -04001081 }
Geoff Langafd7f0a2015-09-09 15:33:31 -04001082 }
1083}
1084
Jamie Madillc564c072017-06-01 12:45:42 -04001085void FramebufferGL::syncClearBufferState(const gl::Context *context,
1086 GLenum buffer,
1087 GLint drawBuffer)
Geoff Langafd7f0a2015-09-09 15:33:31 -04001088{
Geoff Lang61107632018-05-09 11:32:46 -04001089 const FunctionsGL *functions = GetFunctionsGL(context);
1090
1091 if (functions->standard == STANDARD_GL_DESKTOP)
Geoff Langafd7f0a2015-09-09 15:33:31 -04001092 {
Jamie Madill4e71b2b2019-07-08 13:23:38 -04001093 StateManagerGL *stateManager = GetStateManagerGL(context);
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -04001094 const angle::FeaturesGL &features = GetFeaturesGL(context);
Geoff Lang61107632018-05-09 11:32:46 -04001095
Jonah Ryan-Davisbeb0eb22019-06-14 15:10:33 -04001096 if (features.doesSRGBClearsOnLinearFramebufferAttachments.enabled && buffer == GL_COLOR &&
1097 !mIsDefault)
Geoff Langafd7f0a2015-09-09 15:33:31 -04001098 {
1099 // If doing a clear on a color buffer, set SRGB blend enabled only if the color buffer
1100 // is an SRGB format.
Jamie Madill48ef11b2016-04-27 15:21:52 -04001101 const auto &drawbufferState = mState.getDrawBufferStates();
1102 const auto &colorAttachments = mState.getColorAttachments();
Geoff Langafd7f0a2015-09-09 15:33:31 -04001103
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001104 const FramebufferAttachment *attachment = nullptr;
Geoff Langafd7f0a2015-09-09 15:33:31 -04001105 if (drawbufferState[drawBuffer] >= GL_COLOR_ATTACHMENT0 &&
1106 drawbufferState[drawBuffer] < GL_COLOR_ATTACHMENT0 + colorAttachments.size())
1107 {
1108 size_t attachmentIdx =
1109 static_cast<size_t>(drawbufferState[drawBuffer] - GL_COLOR_ATTACHMENT0);
1110 attachment = &colorAttachments[attachmentIdx];
1111 }
1112
1113 if (attachment != nullptr)
1114 {
Geoff Lang61107632018-05-09 11:32:46 -04001115 stateManager->setFramebufferSRGBEnabled(context,
1116 attachment->getColorEncoding() == GL_SRGB);
Geoff Langafd7f0a2015-09-09 15:33:31 -04001117 }
1118 }
1119 else
1120 {
Geoff Lang61107632018-05-09 11:32:46 -04001121 stateManager->setFramebufferSRGBEnabled(context, !mIsDefault);
Geoff Langafd7f0a2015-09-09 15:33:31 -04001122 }
1123 }
1124}
Geoff Lang005a7012017-03-27 13:17:34 -04001125
1126bool FramebufferGL::modifyInvalidateAttachmentsForEmulatedDefaultFBO(
1127 size_t count,
1128 const GLenum *attachments,
1129 std::vector<GLenum> *modifiedAttachments) const
1130{
1131 bool needsModification = mIsDefault && mFramebufferID != 0;
1132 if (!needsModification)
1133 {
1134 return false;
1135 }
1136
1137 modifiedAttachments->resize(count);
1138 for (size_t i = 0; i < count; i++)
1139 {
1140 switch (attachments[i])
1141 {
1142 case GL_COLOR:
1143 (*modifiedAttachments)[i] = GL_COLOR_ATTACHMENT0;
1144 break;
1145
1146 case GL_DEPTH:
1147 (*modifiedAttachments)[i] = GL_DEPTH_ATTACHMENT;
1148 break;
1149
1150 case GL_STENCIL:
1151 (*modifiedAttachments)[i] = GL_STENCIL_ATTACHMENT;
1152 break;
1153
1154 default:
1155 UNREACHABLE();
1156 break;
1157 }
1158 }
1159
1160 return true;
1161}
1162
Jamie Madille39e8f42018-10-05 08:17:38 -04001163angle::Result FramebufferGL::readPixelsRowByRow(const gl::Context *context,
1164 const gl::Rectangle &area,
1165 GLenum format,
1166 GLenum type,
1167 const gl::PixelPackState &pack,
1168 GLubyte *pixels) const
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001169{
Jamie Madille39e8f42018-10-05 08:17:38 -04001170 ContextGL *contextGL = GetImplAs<ContextGL>(context);
Geoff Lang61107632018-05-09 11:32:46 -04001171 const FunctionsGL *functions = GetFunctionsGL(context);
1172 StateManagerGL *stateManager = GetStateManagerGL(context);
1173
Geoff Langca271392017-04-05 12:30:00 -04001174 const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
Frank Henigmanfa36c332017-06-09 18:44:45 -04001175
1176 GLuint rowBytes = 0;
Jamie Madille39e8f42018-10-05 08:17:38 -04001177 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, pack.alignment,
1178 pack.rowLength, &rowBytes));
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001179 GLuint skipBytes = 0;
Jamie Madille39e8f42018-10-05 08:17:38 -04001180 ANGLE_CHECK_GL_MATH(contextGL,
1181 glFormat.computeSkipBytes(type, rowBytes, 0, pack, false, &skipBytes));
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001182
1183 gl::PixelPackState directPack;
Jamie Madillb980c562018-11-27 11:34:27 -05001184 directPack.alignment = 1;
Geoff Lang61107632018-05-09 11:32:46 -04001185 stateManager->setPixelPackState(directPack);
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001186
Frank Henigmanfa36c332017-06-09 18:44:45 -04001187 pixels += skipBytes;
1188 for (GLint y = area.y; y < area.y + area.height; ++y)
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001189 {
Geoff Lang61107632018-05-09 11:32:46 -04001190 functions->readPixels(area.x, y, area.width, 1, format, type, pixels);
Frank Henigmanfa36c332017-06-09 18:44:45 -04001191 pixels += rowBytes;
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001192 }
1193
Jamie Madill7c985f52018-11-29 18:16:17 -05001194 return angle::Result::Continue;
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001195}
1196
Jamie Madille39e8f42018-10-05 08:17:38 -04001197angle::Result FramebufferGL::readPixelsAllAtOnce(const gl::Context *context,
1198 const gl::Rectangle &area,
1199 GLenum format,
1200 GLenum type,
1201 const gl::PixelPackState &pack,
1202 GLubyte *pixels,
1203 bool readLastRowSeparately) const
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001204{
Jamie Madille39e8f42018-10-05 08:17:38 -04001205 ContextGL *contextGL = GetImplAs<ContextGL>(context);
Geoff Lang61107632018-05-09 11:32:46 -04001206 const FunctionsGL *functions = GetFunctionsGL(context);
1207 StateManagerGL *stateManager = GetStateManagerGL(context);
1208
Frank Henigmanfa36c332017-06-09 18:44:45 -04001209 GLint height = area.height - readLastRowSeparately;
1210 if (height > 0)
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001211 {
Geoff Lang61107632018-05-09 11:32:46 -04001212 stateManager->setPixelPackState(pack);
1213 functions->readPixels(area.x, area.y, area.width, height, format, type, pixels);
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001214 }
1215
Frank Henigmanfa36c332017-06-09 18:44:45 -04001216 if (readLastRowSeparately)
1217 {
1218 const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001219
Frank Henigmanfa36c332017-06-09 18:44:45 -04001220 GLuint rowBytes = 0;
Jamie Madille39e8f42018-10-05 08:17:38 -04001221 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, pack.alignment,
1222 pack.rowLength, &rowBytes));
Frank Henigmanfa36c332017-06-09 18:44:45 -04001223 GLuint skipBytes = 0;
Jamie Madille39e8f42018-10-05 08:17:38 -04001224 ANGLE_CHECK_GL_MATH(contextGL,
1225 glFormat.computeSkipBytes(type, rowBytes, 0, pack, false, &skipBytes));
Frank Henigmanfa36c332017-06-09 18:44:45 -04001226
1227 gl::PixelPackState directPack;
Frank Henigmanfa36c332017-06-09 18:44:45 -04001228 directPack.alignment = 1;
Geoff Lang61107632018-05-09 11:32:46 -04001229 stateManager->setPixelPackState(directPack);
Frank Henigmanfa36c332017-06-09 18:44:45 -04001230
1231 pixels += skipBytes + (area.height - 1) * rowBytes;
Geoff Lang61107632018-05-09 11:32:46 -04001232 functions->readPixels(area.x, area.y + area.height - 1, area.width, 1, format, type,
1233 pixels);
Frank Henigmanfa36c332017-06-09 18:44:45 -04001234 }
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001235
Jamie Madill7c985f52018-11-29 18:16:17 -05001236 return angle::Result::Continue;
Corentin Wallez9a8d3662016-09-22 12:18:29 -04001237}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001238} // namespace rx