| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2005 Blender Foundation. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 11:23:17 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup gpu | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_blenlib.h"
 | 
					
						
							|  |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | #include "BLI_math_base.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 19:57:58 +01:00
										 |  |  | #include "GPU_batch.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-04 20:33:23 +02:00
										 |  |  | #include "GPU_draw.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-10 17:18:29 +02:00
										 |  |  | #include "GPU_extensions.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | #include "GPU_framebuffer.h"
 | 
					
						
							|  |  |  | #include "GPU_shader.h"
 | 
					
						
							|  |  |  | #include "GPU_texture.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-19 15:48:13 +02:00
										 |  |  | #include "gpu_private.h"
 | 
					
						
							|  |  |  | #include "gpu_context_private.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-11 20:50:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | typedef enum { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPU_FB_DEPTH_ATTACHMENT = 0, | 
					
						
							|  |  |  |   GPU_FB_DEPTH_STENCIL_ATTACHMENT, | 
					
						
							|  |  |  |   GPU_FB_COLOR_ATTACHMENT0, | 
					
						
							|  |  |  |   GPU_FB_COLOR_ATTACHMENT1, | 
					
						
							|  |  |  |   GPU_FB_COLOR_ATTACHMENT2, | 
					
						
							|  |  |  |   GPU_FB_COLOR_ATTACHMENT3, | 
					
						
							|  |  |  |   GPU_FB_COLOR_ATTACHMENT4, | 
					
						
							| 
									
										
										
										
											2019-08-22 16:04:25 +02:00
										 |  |  |   GPU_FB_COLOR_ATTACHMENT5, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Number of maximum output slots.
 | 
					
						
							| 
									
										
										
										
											2019-08-22 16:04:25 +02:00
										 |  |  |    * We support 6 outputs for now (usually we wouldn't need more to preserve fill rate). */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to
 | 
					
						
							|  |  |  |    * the maximum number of COLOR attachments specified by glDrawBuffers. */ | 
					
						
							|  |  |  |   GPU_FB_MAX_ATTACHEMENT, | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } GPUAttachmentType; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define GPU_FB_MAX_COLOR_ATTACHMENT (GPU_FB_MAX_ATTACHEMENT - GPU_FB_COLOR_ATTACHMENT0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define GPU_FB_DIRTY_DRAWBUFFER (1 << 15)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define GPU_FB_ATTACHEMENT_IS_DIRTY(flag, type) ((flag & (1 << type)) != 0)
 | 
					
						
							|  |  |  | #define GPU_FB_ATTACHEMENT_SET_DIRTY(flag, type) (flag |= (1 << type))
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct GPUFrameBuffer { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUContext *ctx; | 
					
						
							|  |  |  |   GLuint object; | 
					
						
							|  |  |  |   GPUAttachment attachments[GPU_FB_MAX_ATTACHEMENT]; | 
					
						
							|  |  |  |   uint16_t dirty_flag; | 
					
						
							|  |  |  |   int width, height; | 
					
						
							|  |  |  |   bool multisample; | 
					
						
							|  |  |  |   /* TODO Check that we always use the right context when binding
 | 
					
						
							|  |  |  |    * (FBOs are not shared across ogl contexts). */ | 
					
						
							|  |  |  |   // void *ctx;
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static GLenum convert_attachment_type_to_gl(GPUAttachmentType type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   static const GLenum table[] = { | 
					
						
							|  |  |  |       [GPU_FB_DEPTH_ATTACHMENT] = GL_DEPTH_ATTACHMENT, | 
					
						
							|  |  |  |       [GPU_FB_DEPTH_STENCIL_ATTACHMENT] = GL_DEPTH_STENCIL_ATTACHMENT, | 
					
						
							|  |  |  |       [GPU_FB_COLOR_ATTACHMENT0] = GL_COLOR_ATTACHMENT0, | 
					
						
							|  |  |  |       [GPU_FB_COLOR_ATTACHMENT1] = GL_COLOR_ATTACHMENT1, | 
					
						
							|  |  |  |       [GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2, | 
					
						
							|  |  |  |       [GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3, | 
					
						
							|  |  |  |       [GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4, | 
					
						
							| 
									
										
										
										
											2019-08-22 16:04:25 +02:00
										 |  |  |       [GPU_FB_COLOR_ATTACHMENT5] = GL_COLOR_ATTACHMENT5, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   }; | 
					
						
							|  |  |  |   return table[type]; | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   switch (GPU_texture_format(tex)) { | 
					
						
							|  |  |  |     case GPU_DEPTH_COMPONENT32F: | 
					
						
							|  |  |  |     case GPU_DEPTH_COMPONENT24: | 
					
						
							|  |  |  |     case GPU_DEPTH_COMPONENT16: | 
					
						
							|  |  |  |       return GPU_FB_DEPTH_ATTACHMENT; | 
					
						
							|  |  |  |     case GPU_DEPTH24_STENCIL8: | 
					
						
							|  |  |  |     case GPU_DEPTH32F_STENCIL8: | 
					
						
							|  |  |  |       return GPU_FB_DEPTH_STENCIL_ATTACHMENT; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return GPU_FB_COLOR_ATTACHMENT0 + slot; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:15:43 +11:00
										 |  |  | static GLenum convert_buffer_bits_to_gl(eGPUFrameBufferBits bits) | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLbitfield mask = 0; | 
					
						
							|  |  |  |   mask |= (bits & GPU_DEPTH_BIT) ? GL_DEPTH_BUFFER_BIT : 0; | 
					
						
							|  |  |  |   mask |= (bits & GPU_STENCIL_BIT) ? GL_STENCIL_BUFFER_BIT : 0; | 
					
						
							|  |  |  |   mask |= (bits & GPU_COLOR_BIT) ? GL_COLOR_BUFFER_BIT : 0; | 
					
						
							|  |  |  |   return mask; | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static GPUTexture *framebuffer_get_depth_tex(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GPUTexture *framebuffer_get_color_tex(GPUFrameBuffer *fb, int slot) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return fb->attachments[GPU_FB_COLOR_ATTACHMENT0 + slot].tex; | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 20:18:44 +10:00
										 |  |  | static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const char *format = "GPUFrameBuffer: framebuffer status %s\n"; | 
					
						
							|  |  |  |   const char *err = "unknown"; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-18 18:11:16 +02:00
										 |  |  | #define FORMAT_STATUS(X) \
 | 
					
						
							| 
									
										
										
										
											2019-09-21 11:34:39 +10:00
										 |  |  |   case GL_FRAMEBUFFER_##X: { \ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     err = "GL_FRAMEBUFFER_" #X; \ | 
					
						
							| 
									
										
										
										
											2019-09-21 11:34:39 +10:00
										 |  |  |     break; \ | 
					
						
							|  |  |  |   } \ | 
					
						
							|  |  |  |     ((void)0) | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   switch (status) { | 
					
						
							|  |  |  |     /* success */ | 
					
						
							| 
									
										
										
										
											2019-06-18 18:11:16 +02:00
										 |  |  |     FORMAT_STATUS(COMPLETE); | 
					
						
							|  |  |  |     /* errors shared by OpenGL desktop & ES */ | 
					
						
							|  |  |  |     FORMAT_STATUS(INCOMPLETE_ATTACHMENT); | 
					
						
							|  |  |  |     FORMAT_STATUS(INCOMPLETE_MISSING_ATTACHMENT); | 
					
						
							|  |  |  |     FORMAT_STATUS(UNSUPPORTED); | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | #if 0 /* for OpenGL ES only */
 | 
					
						
							| 
									
										
										
										
											2019-06-18 18:11:16 +02:00
										 |  |  |     FORMAT_STATUS(INCOMPLETE_DIMENSIONS); | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | #else /* for desktop GL only */
 | 
					
						
							| 
									
										
										
										
											2019-06-18 18:11:16 +02:00
										 |  |  |     FORMAT_STATUS(INCOMPLETE_DRAW_BUFFER); | 
					
						
							|  |  |  |     FORMAT_STATUS(INCOMPLETE_READ_BUFFER); | 
					
						
							|  |  |  |     FORMAT_STATUS(INCOMPLETE_MULTISAMPLE); | 
					
						
							|  |  |  |     FORMAT_STATUS(UNDEFINED); | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-18 18:11:16 +02:00
										 |  |  | #undef FORMAT_STATUS
 | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (err_out) { | 
					
						
							|  |  |  |     BLI_snprintf(err_out, 256, format, err); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     fprintf(stderr, format, err); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-11 20:50:14 +02:00
										 |  |  | void gpu_framebuffer_module_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void gpu_framebuffer_module_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 18:16:08 +02:00
										 |  |  | GPUFrameBuffer *GPU_framebuffer_active_get(void) | 
					
						
							| 
									
										
										
										
											2018-06-11 20:50:14 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUContext *ctx = GPU_context_active_get(); | 
					
						
							|  |  |  |   if (ctx) { | 
					
						
							|  |  |  |     return gpu_context_active_framebuffer_get(ctx); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-11 20:50:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 18:16:08 +02:00
										 |  |  | static void gpu_framebuffer_current_set(GPUFrameBuffer *fb) | 
					
						
							| 
									
										
										
										
											2018-06-11 20:50:14 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUContext *ctx = GPU_context_active_get(); | 
					
						
							|  |  |  |   if (ctx) { | 
					
						
							|  |  |  |     gpu_context_active_framebuffer_set(ctx, fb); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-11 20:50:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | /* GPUFrameBuffer */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GPUFrameBuffer *GPU_framebuffer_create(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* We generate the FB object later at first use in order to
 | 
					
						
							|  |  |  |    * create the framebuffer in the right opengl context. */ | 
					
						
							|  |  |  |   return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static void gpu_framebuffer_init(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   fb->object = GPU_fbo_alloc(); | 
					
						
							|  |  |  |   fb->ctx = GPU_context_active_get(); | 
					
						
							|  |  |  |   gpu_context_add_framebuffer(fb->ctx, fb); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_framebuffer_free(GPUFrameBuffer *fb) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { | 
					
						
							|  |  |  |     if (fb->attachments[type].tex != NULL) { | 
					
						
							|  |  |  |       GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (fb->object != 0) { | 
					
						
							|  |  |  |     /* This restores the framebuffer if it was bound */ | 
					
						
							|  |  |  |     GPU_fbo_free(fb->object, fb->ctx); | 
					
						
							|  |  |  |     gpu_context_remove_framebuffer(fb->ctx, fb); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (GPU_framebuffer_active_get() == fb) { | 
					
						
							|  |  |  |     gpu_framebuffer_current_set(NULL); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MEM_freeN(fb); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | /* ---------- Attach ----------- */ | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void gpu_framebuffer_texture_attach_ex( | 
					
						
							|  |  |  |     GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) { | 
					
						
							|  |  |  |     fprintf(stderr, | 
					
						
							|  |  |  |             "Attaching to index %d framebuffer slot unsupported. " | 
					
						
							|  |  |  |             "Use at most %d\n", | 
					
						
							|  |  |  |             slot, | 
					
						
							|  |  |  |             GPU_FB_MAX_COLOR_ATTACHMENT); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUAttachmentType type = attachment_type_from_tex(tex, slot); | 
					
						
							|  |  |  |   GPUAttachment *attachment = &fb->attachments[type]; | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if ((attachment->tex == tex) && (attachment->mip == mip) && (attachment->layer == layer)) { | 
					
						
							|  |  |  |     return; /* Exact same texture already bound here. */ | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (attachment->tex != NULL) { | 
					
						
							|  |  |  |     GPU_framebuffer_texture_detach(fb, attachment->tex); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (attachment->tex == NULL) { | 
					
						
							|  |  |  |     GPU_texture_attach_framebuffer(tex, fb, type); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   attachment->tex = tex; | 
					
						
							|  |  |  |   attachment->mip = mip; | 
					
						
							|  |  |  |   attachment->layer = layer; | 
					
						
							|  |  |  |   GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip); | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void GPU_framebuffer_texture_layer_attach( | 
					
						
							|  |  |  |     GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* NOTE: We could support 1D ARRAY texture. */ | 
					
						
							|  |  |  |   BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY); | 
					
						
							|  |  |  |   gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip); | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void GPU_framebuffer_texture_cubeface_attach( | 
					
						
							|  |  |  |     GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(GPU_texture_cube(tex)); | 
					
						
							|  |  |  |   gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | /* ---------- Detach ----------- */ | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *fb, GPUTexture *tex, int type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUAttachment *attachment = &fb->attachments[type]; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (attachment->tex != tex) { | 
					
						
							|  |  |  |     fprintf(stderr, | 
					
						
							|  |  |  |             "Warning, attempting to detach Texture %p from framebuffer %p " | 
					
						
							|  |  |  |             "but texture is not attached.\n", | 
					
						
							|  |  |  |             tex, | 
					
						
							|  |  |  |             fb); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   attachment->tex = NULL; | 
					
						
							|  |  |  |   GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUAttachmentType type = GPU_texture_detach_framebuffer(tex, fb); | 
					
						
							|  |  |  |   GPU_framebuffer_texture_detach_slot(fb, tex, type); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | /* ---------- Config (Attach & Detach) ----------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * First GPUAttachment in *config is always the depth/depth_stencil buffer. | 
					
						
							|  |  |  |  * Following GPUAttachments are color buffers. | 
					
						
							|  |  |  |  * Setting GPUAttachment.mip to -1 will leave the texture in this slot. | 
					
						
							|  |  |  |  * Setting GPUAttachment.tex to NULL will detach the texture in this slot. | 
					
						
							| 
									
										
										
										
											2019-03-19 15:17:46 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-07-08 13:14:49 +02:00
										 |  |  | void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (config[0].tex) { | 
					
						
							|  |  |  |     BLI_assert(GPU_texture_depth(config[0].tex)); | 
					
						
							|  |  |  |     gpu_framebuffer_texture_attach_ex(fb, config[0].tex, 0, config[0].layer, config[0].mip); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (config[0].mip == -1) { | 
					
						
							|  |  |  |     /* Leave texture attached */ | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex != NULL) { | 
					
						
							|  |  |  |     GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) { | 
					
						
							|  |  |  |     GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int slot = 0; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (int i = 1; i < config_len; i++, slot++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if (config[i].tex != NULL) { | 
					
						
							|  |  |  |       BLI_assert(GPU_texture_depth(config[i].tex) == false); | 
					
						
							|  |  |  |       gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (config[i].mip != -1) { | 
					
						
							|  |  |  |       GPUTexture *tex = framebuffer_get_color_tex(fb, slot); | 
					
						
							|  |  |  |       if (tex != NULL) { | 
					
						
							|  |  |  |         GPU_framebuffer_texture_detach(fb, tex); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | /* ---------- Bind / Restore ----------- */ | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static void gpu_framebuffer_attachment_attach(GPUAttachment *attach, GPUAttachmentType attach_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int tex_bind = GPU_texture_opengl_bindcode(attach->tex); | 
					
						
							|  |  |  |   GLenum gl_attachment = convert_attachment_type_to_gl(attach_type); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (attach->layer > -1) { | 
					
						
							|  |  |  |     if (GPU_texture_cube(attach->tex)) { | 
					
						
							|  |  |  |       glFramebufferTexture2D(GL_FRAMEBUFFER, | 
					
						
							|  |  |  |                              gl_attachment, | 
					
						
							|  |  |  |                              GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach->layer, | 
					
						
							|  |  |  |                              tex_bind, | 
					
						
							|  |  |  |                              attach->mip); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       glFramebufferTextureLayer( | 
					
						
							|  |  |  |           GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip, attach->layer); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment), | 
					
						
							|  |  |  |                                               GPUAttachmentType attach_type) | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLenum gl_attachment = convert_attachment_type_to_gl(attach_type); | 
					
						
							|  |  |  |   glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; | 
					
						
							|  |  |  |   int numslots = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLI_assert(GPU_framebuffer_active_get() == fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Update attachments */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (type >= GPU_FB_COLOR_ATTACHMENT0) { | 
					
						
							|  |  |  |       if (fb->attachments[type].tex) { | 
					
						
							|  |  |  |         gl_attachments[numslots] = convert_attachment_type_to_gl(type); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         gl_attachments[numslots] = GL_NONE; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       numslots++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (fb->attachments[type].tex != NULL) { | 
					
						
							|  |  |  |       gpu_framebuffer_attachment_attach(&fb->attachments[type], type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fb->multisample = (GPU_texture_samples(fb->attachments[type].tex) > 0); | 
					
						
							|  |  |  |       fb->width = GPU_texture_width(fb->attachments[type].tex); | 
					
						
							|  |  |  |       fb->height = GPU_texture_height(fb->attachments[type].tex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       gpu_framebuffer_attachment_detach(&fb->attachments[type], type); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   fb->dirty_flag = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Update draw buffers (color targets)
 | 
					
						
							|  |  |  |    * This state is saved in the FBO */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   if (numslots) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     glDrawBuffers(numslots, gl_attachments); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     glDrawBuffer(GL_NONE); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-05 20:59:22 -02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Hack to solve the problem of some bugged AMD GPUs (see `GPU_unused_fb_slot_workaround`). | 
					
						
							|  |  |  |  * If there is an empty color slot between the color slots, | 
					
						
							|  |  |  |  * all textures after this slot are apparently skipped/discarded. | 
					
						
							| 
									
										
										
										
											2019-03-19 15:17:46 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-12-05 20:59:22 -02:00
										 |  |  | static void gpu_framebuffer_update_attachments_and_fill_empty_slots(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; | 
					
						
							|  |  |  |   int dummy_tex = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLI_assert(GPU_framebuffer_active_get() == fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Update attachments */ | 
					
						
							|  |  |  |   for (GPUAttachmentType type = GPU_FB_MAX_ATTACHEMENT; type--;) { | 
					
						
							|  |  |  |     GPUTexture *tex = fb->attachments[type].tex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type >= GPU_FB_COLOR_ATTACHMENT0) { | 
					
						
							|  |  |  |       int slot = type - GPU_FB_COLOR_ATTACHMENT0; | 
					
						
							|  |  |  |       if (tex != NULL || (dummy_tex != 0)) { | 
					
						
							|  |  |  |         gl_attachments[slot] = convert_attachment_type_to_gl(type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (dummy_tex == 0) { | 
					
						
							|  |  |  |           dummy_tex = GPU_texture_opengl_bindcode(tex); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         gl_attachments[slot] = GL_NONE; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       dummy_tex = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((dummy_tex != 0) && tex == NULL) { | 
					
						
							|  |  |  |       /* Fill empty slot */ | 
					
						
							|  |  |  |       glFramebufferTexture(GL_FRAMEBUFFER, convert_attachment_type_to_gl(type), dummy_tex, 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type)) { | 
					
						
							|  |  |  |       if (tex != NULL) { | 
					
						
							|  |  |  |         gpu_framebuffer_attachment_attach(&fb->attachments[type], type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fb->multisample = (GPU_texture_samples(tex) > 0); | 
					
						
							|  |  |  |         fb->width = GPU_texture_width(tex); | 
					
						
							|  |  |  |         fb->height = GPU_texture_height(tex); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         gpu_framebuffer_attachment_detach(&fb->attachments[type], type); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   fb->dirty_flag = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Update draw buffers (color targets)
 | 
					
						
							|  |  |  |    * This state is saved in the FBO */ | 
					
						
							|  |  |  |   glDrawBuffers(GPU_FB_MAX_COLOR_ATTACHMENT, gl_attachments); | 
					
						
							| 
									
										
										
										
											2018-12-05 20:59:22 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 15:24:13 +01:00
										 |  |  | #define FRAMEBUFFER_STACK_DEPTH 16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUFrameBuffer *framebuffers[FRAMEBUFFER_STACK_DEPTH]; | 
					
						
							|  |  |  |   uint top; | 
					
						
							| 
									
										
										
										
											2018-12-30 15:14:00 +11:00
										 |  |  | } FrameBufferStack = {{0}}; | 
					
						
							| 
									
										
										
										
											2018-11-06 15:24:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void gpuPushFrameBuffer(GPUFrameBuffer *fbo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(FrameBufferStack.top < FRAMEBUFFER_STACK_DEPTH); | 
					
						
							|  |  |  |   FrameBufferStack.framebuffers[FrameBufferStack.top] = fbo; | 
					
						
							|  |  |  |   FrameBufferStack.top++; | 
					
						
							| 
									
										
										
										
											2018-11-06 15:24:13 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GPUFrameBuffer *gpuPopFrameBuffer(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(FrameBufferStack.top > 0); | 
					
						
							|  |  |  |   FrameBufferStack.top--; | 
					
						
							|  |  |  |   return FrameBufferStack.framebuffers[FrameBufferStack.top]; | 
					
						
							| 
									
										
										
										
											2018-11-06 15:24:13 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef FRAMEBUFFER_STACK_DEPTH
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | void GPU_framebuffer_bind(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   if (fb->object == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     gpu_framebuffer_init(fb); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   if (GPU_framebuffer_active_get() != fb) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     glBindFramebuffer(GL_FRAMEBUFFER, fb->object); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   gpu_framebuffer_current_set(fb); | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (fb->dirty_flag != 0) { | 
					
						
							|  |  |  |     if (GPU_unused_fb_slot_workaround()) { | 
					
						
							|  |  |  |       /* XXX: Please AMD, fix this. */ | 
					
						
							|  |  |  |       gpu_framebuffer_update_attachments_and_fill_empty_slots(fb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       gpu_framebuffer_update_attachments(fb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* TODO manually check for errors? */ | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   char err_out[256]; | 
					
						
							|  |  |  |   if (!GPU_framebuffer_check_valid(fb, err_out)) { | 
					
						
							|  |  |  |     printf("Invalid %s\n", err_out); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   if (fb->multisample) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     glEnable(GL_MULTISAMPLE); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-26 14:01:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   glViewport(0, 0, fb->width, fb->height); | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_framebuffer_restore(void) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (GPU_framebuffer_active_get() != NULL) { | 
					
						
							| 
									
										
										
										
											2019-06-01 17:54:07 +02:00
										 |  |  |     glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default()); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     gpu_framebuffer_current_set(NULL); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | bool GPU_framebuffer_bound(GPUFrameBuffer *fb) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return (fb == GPU_framebuffer_active_get()) && (fb->object != 0); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   if (!GPU_framebuffer_bound(fb)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPU_framebuffer_bind(fb); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-02-17 14:05:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | 
					
						
							| 
									
										
										
										
											2016-08-19 00:52:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (status != GL_FRAMEBUFFER_COMPLETE) { | 
					
						
							|  |  |  |     GPU_framebuffer_restore(); | 
					
						
							|  |  |  |     gpu_print_framebuffer_error(status, err_out); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-08-19 00:52:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | /* ---------- Framebuffer Operations ----------- */ | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | #define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(GPU_framebuffer_bound(_fb)); \ | 
					
						
							| 
									
										
										
										
											2019-04-20 11:28:21 +02:00
										 |  |  |   UNUSED_VARS_NDEBUG(_fb); \ | 
					
						
							|  |  |  |   ((void)0) | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Needs to be done after binding. */ | 
					
						
							|  |  |  | void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   glViewport(x, y, w, h); | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void GPU_framebuffer_clear(GPUFrameBuffer *fb, | 
					
						
							|  |  |  |                            eGPUFrameBufferBits buffers, | 
					
						
							|  |  |  |                            const float clear_col[4], | 
					
						
							|  |  |  |                            float clear_depth, | 
					
						
							|  |  |  |                            uint clear_stencil) | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (buffers & GPU_COLOR_BIT) { | 
					
						
							|  |  |  |     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | 
					
						
							|  |  |  |     glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (buffers & GPU_DEPTH_BIT) { | 
					
						
							|  |  |  |     glDepthMask(GL_TRUE); | 
					
						
							|  |  |  |     glClearDepth(clear_depth); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (buffers & GPU_STENCIL_BIT) { | 
					
						
							|  |  |  |     glStencilMask(0xFF); | 
					
						
							|  |  |  |     glClearStencil(clear_stencil); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLbitfield mask = convert_buffer_bits_to_gl(buffers); | 
					
						
							|  |  |  |   glClear(mask); | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLenum type = GL_DEPTH_COMPONENT; | 
					
						
							|  |  |  |   glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ | 
					
						
							|  |  |  |   glReadPixels(x, y, w, h, type, GL_FLOAT, data); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_framebuffer_read_color( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GLenum type; | 
					
						
							|  |  |  |   switch (channels) { | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |       type = GL_RED; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |       type = GL_RG; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 3: | 
					
						
							|  |  |  |       type = GL_RGB; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 4: | 
					
						
							|  |  |  |       type = GL_RGBA; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       BLI_assert(false && "wrong number of read channels"); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); | 
					
						
							|  |  |  |   glReadPixels(x, y, w, h, type, GL_FLOAT, data); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* read_slot and write_slot are only used for color buffers. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, | 
					
						
							|  |  |  |                           int read_slot, | 
					
						
							|  |  |  |                           GPUFrameBuffer *fb_write, | 
					
						
							|  |  |  |                           int write_slot, | 
					
						
							|  |  |  |                           eGPUFrameBufferBits blit_buffers) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   BLI_assert(blit_buffers != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Framebuffers must be up to date. This simplify this function. */ | 
					
						
							|  |  |  |   if (fb_read->dirty_flag != 0 || fb_read->object == 0) { | 
					
						
							|  |  |  |     GPU_framebuffer_bind(fb_read); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (fb_write->dirty_flag != 0 || fb_write->object == 0) { | 
					
						
							|  |  |  |     GPU_framebuffer_bind(fb_write); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const bool do_color = (blit_buffers & GPU_COLOR_BIT); | 
					
						
							|  |  |  |   const bool do_depth = (blit_buffers & GPU_DEPTH_BIT); | 
					
						
							|  |  |  |   const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUTexture *read_tex = ((do_depth || do_stencil) ? | 
					
						
							|  |  |  |                               framebuffer_get_depth_tex(fb_read) : | 
					
						
							|  |  |  |                               framebuffer_get_color_tex(fb_read, read_slot)); | 
					
						
							|  |  |  |   GPUTexture *write_tex = ((do_depth || do_stencil) ? | 
					
						
							|  |  |  |                                framebuffer_get_depth_tex(fb_write) : | 
					
						
							|  |  |  |                                framebuffer_get_color_tex(fb_write, read_slot)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (do_depth) { | 
					
						
							|  |  |  |     BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex)); | 
					
						
							|  |  |  |     BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (do_stencil) { | 
					
						
							|  |  |  |     BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex)); | 
					
						
							|  |  |  |     BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (GPU_texture_samples(write_tex) != 0 || GPU_texture_samples(read_tex) != 0) { | 
					
						
							|  |  |  |     /* Can only blit multisample textures to another texture of the same size. */ | 
					
						
							|  |  |  |     BLI_assert((fb_read->width == fb_write->width) && (fb_read->height == fb_write->height)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); | 
					
						
							|  |  |  |   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (do_color) { | 
					
						
							|  |  |  |     glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot); | 
					
						
							|  |  |  |     glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot); | 
					
						
							|  |  |  |     /* XXX we messed with the glDrawBuffer, this will reset the
 | 
					
						
							|  |  |  |      * glDrawBuffers the next time we bind fb_write. */ | 
					
						
							|  |  |  |     fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glBlitFramebuffer(0, | 
					
						
							|  |  |  |                     0, | 
					
						
							|  |  |  |                     fb_read->width, | 
					
						
							|  |  |  |                     fb_read->height, | 
					
						
							|  |  |  |                     0, | 
					
						
							|  |  |  |                     0, | 
					
						
							|  |  |  |                     fb_write->width, | 
					
						
							|  |  |  |                     fb_write->height, | 
					
						
							|  |  |  |                     mask, | 
					
						
							|  |  |  |                     GL_NEAREST); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Restore previous framebuffer */ | 
					
						
							|  |  |  |   if (fb_write == prev_fb) { | 
					
						
							|  |  |  |     GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (prev_fb) { | 
					
						
							|  |  |  |     glBindFramebuffer(GL_FRAMEBUFFER, prev_fb->object); | 
					
						
							|  |  |  |     gpu_framebuffer_current_set(prev_fb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-06-01 17:54:07 +02:00
										 |  |  |     glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default()); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     gpu_framebuffer_current_set(NULL); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-15 15:15:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2019-06-12 09:04:10 +10:00
										 |  |  |  * Use this if you need to custom down-sample your texture and use the previous mip level as input. | 
					
						
							| 
									
										
										
										
											2019-04-22 01:45:43 +10:00
										 |  |  |  * This function only takes care of the correct texture handling. | 
					
						
							|  |  |  |  * It execute the callback for each texture level. | 
					
						
							| 
									
										
										
										
											2019-03-19 15:17:46 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb, | 
					
						
							|  |  |  |                                           int max_lvl, | 
					
						
							|  |  |  |                                           void (*callback)(void *userData, int level), | 
					
						
							|  |  |  |                                           void *userData) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   /* Framebuffer must be up to date and bound. This simplify this function. */ | 
					
						
							|  |  |  |   if (GPU_framebuffer_active_get() != fb || fb->dirty_flag != 0 || fb->object == 0) { | 
					
						
							|  |  |  |     GPU_framebuffer_bind(fb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* HACK: We make the framebuffer appear not bound in order to
 | 
					
						
							|  |  |  |    * not trigger any error in GPU_texture_bind().  */ | 
					
						
							|  |  |  |   GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); | 
					
						
							|  |  |  |   gpu_framebuffer_current_set(NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int levels = floor(log2(max_ii(fb->width, fb->height))); | 
					
						
							|  |  |  |   max_lvl = min_ii(max_lvl, levels); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  |   int current_dim[2] = {fb->width, fb->height}; | 
					
						
							|  |  |  |   for (i = 1; i < max_lvl + 1; i++) { | 
					
						
							|  |  |  |     /* calculate next viewport size */ | 
					
						
							|  |  |  |     current_dim[0] = max_ii(current_dim[0] / 2, 1); | 
					
						
							|  |  |  |     current_dim[1] = max_ii(current_dim[1] / 2, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       if (fb->attachments[type].tex != NULL) { | 
					
						
							|  |  |  |         /* Some Intel HDXXX have issue with rendering to a mipmap that is below
 | 
					
						
							|  |  |  |          * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case | 
					
						
							|  |  |  |          * we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */ | 
					
						
							|  |  |  |         int next_lvl = (GPU_mip_render_workaround()) ? i : i - 1; | 
					
						
							|  |  |  |         /* bind next level for rendering but first restrict fetches only to previous level */ | 
					
						
							|  |  |  |         GPUTexture *tex = fb->attachments[type].tex; | 
					
						
							|  |  |  |         GPU_texture_bind(tex, 0); | 
					
						
							|  |  |  |         glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1); | 
					
						
							|  |  |  |         glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, next_lvl); | 
					
						
							|  |  |  |         GPU_texture_unbind(tex); | 
					
						
							|  |  |  |         /* copy attachment and replace miplevel. */ | 
					
						
							|  |  |  |         GPUAttachment attachment = fb->attachments[type]; | 
					
						
							|  |  |  |         attachment.mip = i; | 
					
						
							|  |  |  |         gpu_framebuffer_attachment_attach(&attachment, type); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     glViewport(0, 0, current_dim[0], current_dim[1]); | 
					
						
							|  |  |  |     callback(userData, i); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |     if (current_dim[0] == 1 && current_dim[1] == 1) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if (fb->attachments[type].tex != NULL) { | 
					
						
							|  |  |  |       /* reset mipmap level range */ | 
					
						
							|  |  |  |       GPUTexture *tex = fb->attachments[type].tex; | 
					
						
							|  |  |  |       GPU_texture_bind(tex, 0); | 
					
						
							|  |  |  |       glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0); | 
					
						
							|  |  |  |       glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); | 
					
						
							|  |  |  |       GPU_texture_unbind(tex); | 
					
						
							|  |  |  |       /* Reattach original level */ | 
					
						
							|  |  |  |       /* NOTE: This is not necessary but this makes the FBO config
 | 
					
						
							|  |  |  |        *       remain in sync with the GPUFrameBuffer config. */ | 
					
						
							|  |  |  |       gpu_framebuffer_attachment_attach(&fb->attachments[type], type); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   gpu_framebuffer_current_set(prev_fb); | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | /* GPUOffScreen */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  | #define MAX_CTX_FB_LEN 3
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | struct GPUOffScreen { | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   struct { | 
					
						
							|  |  |  |     GPUContext *ctx; | 
					
						
							|  |  |  |     GPUFrameBuffer *fb; | 
					
						
							|  |  |  |   } framebuffers[MAX_CTX_FB_LEN]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUTexture *color; | 
					
						
							|  |  |  |   GPUTexture *depth; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  | /* Returns the correct framebuffer for the current context. */ | 
					
						
							|  |  |  | static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GPUContext *ctx = GPU_context_active_get(); | 
					
						
							|  |  |  |   BLI_assert(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < MAX_CTX_FB_LEN; i++) { | 
					
						
							|  |  |  |     if (ofs->framebuffers[i].fb == NULL) { | 
					
						
							|  |  |  |       ofs->framebuffers[i].ctx = ctx; | 
					
						
							|  |  |  |       GPU_framebuffer_ensure_config( | 
					
						
							|  |  |  |           &ofs->framebuffers[i].fb, | 
					
						
							|  |  |  |           {GPU_ATTACHMENT_TEXTURE(ofs->depth), GPU_ATTACHMENT_TEXTURE(ofs->color)}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ofs->framebuffers[i].ctx == ctx) { | 
					
						
							|  |  |  |       return ofs->framebuffers[i].fb; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* List is full, this should never happen or
 | 
					
						
							|  |  |  |    * it might just slow things down if it happens | 
					
						
							| 
									
										
										
										
											2019-07-07 15:38:41 +10:00
										 |  |  |    * regularly. In this case we just empty the list | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |    * and start over. This is most likely never going | 
					
						
							|  |  |  |    * to happen under normal usage. */ | 
					
						
							|  |  |  |   BLI_assert(0); | 
					
						
							|  |  |  |   printf( | 
					
						
							|  |  |  |       "Warning: GPUOffscreen used in more than 3 GPUContext. " | 
					
						
							|  |  |  |       "This may create performance drop.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < MAX_CTX_FB_LEN; i++) { | 
					
						
							|  |  |  |     GPU_framebuffer_free(ofs->framebuffers[i].fb); | 
					
						
							|  |  |  |     ofs->framebuffers[i].fb = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return gpu_offscreen_fb_get(ofs); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPUOffScreen *GPU_offscreen_create( | 
					
						
							|  |  |  |     int width, int height, int samples, bool depth, bool high_bitdepth, char err_out[256]) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUOffScreen *ofs; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Sometimes areas can have 0 height or width and this will
 | 
					
						
							|  |  |  |    * create a 1D texture which we don't want. */ | 
					
						
							|  |  |  |   height = max_ii(1, height); | 
					
						
							|  |  |  |   width = max_ii(1, width); | 
					
						
							| 
									
										
										
										
											2019-01-22 16:30:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ofs->color = GPU_texture_create_2d_multisample( | 
					
						
							|  |  |  |       width, height, (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (depth) { | 
					
						
							|  |  |  |     ofs->depth = GPU_texture_create_2d_multisample( | 
					
						
							|  |  |  |         width, height, GPU_DEPTH24_STENCIL8, NULL, samples, err_out); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if ((depth && !ofs->depth) || !ofs->color) { | 
					
						
							|  |  |  |     GPU_offscreen_free(ofs); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-04-20 20:51:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   gpuPushAttr(GPU_VIEWPORT_BIT); | 
					
						
							| 
									
										
										
										
											2018-04-20 20:51:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   GPUFrameBuffer *fb = gpu_offscreen_fb_get(ofs); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* check validity at the very end! */ | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   if (!GPU_framebuffer_check_valid(fb, err_out)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPU_offscreen_free(ofs); | 
					
						
							|  |  |  |     gpuPopAttr(); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPU_framebuffer_restore(); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   gpuPopAttr(); | 
					
						
							| 
									
										
										
										
											2018-04-20 20:51:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return ofs; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_offscreen_free(GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   for (int i = 0; i < MAX_CTX_FB_LEN; i++) { | 
					
						
							|  |  |  |     if (ofs->framebuffers[i].fb) { | 
					
						
							|  |  |  |       GPU_framebuffer_free(ofs->framebuffers[i].fb); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (ofs->color) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPU_texture_free(ofs->color); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (ofs->depth) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPU_texture_free(ofs->depth); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:32:37 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-04 09:09:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MEM_freeN(ofs); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (save) { | 
					
						
							|  |  |  |     gpuPushAttr(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT); | 
					
						
							|  |  |  |     GPUFrameBuffer *fb = GPU_framebuffer_active_get(); | 
					
						
							|  |  |  |     gpuPushFrameBuffer(fb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   glDisable(GL_SCISSOR_TEST); | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); | 
					
						
							|  |  |  |   GPU_framebuffer_bind(ofs_fb); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUFrameBuffer *fb = NULL; | 
					
						
							| 
									
										
										
										
											2018-11-06 15:24:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (restore) { | 
					
						
							|  |  |  |     gpuPopAttr(); | 
					
						
							|  |  |  |     fb = gpuPopFrameBuffer(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-06 15:24:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (fb) { | 
					
						
							|  |  |  |     GPU_framebuffer_bind(fb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     GPU_framebuffer_restore(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 10:22:37 +02:00
										 |  |  | void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const int w = GPU_texture_width(ofs->color); | 
					
						
							|  |  |  |   const int h = GPU_texture_height(ofs->color); | 
					
						
							| 
									
										
										
										
											2018-04-27 10:22:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs_fb->object); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); | 
					
						
							| 
									
										
										
										
											2018-04-27 10:22:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (status == GL_FRAMEBUFFER_COMPLETE) { | 
					
						
							|  |  |  |     glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, GL_COLOR_BUFFER_BIT, GL_NEAREST); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     gpu_print_framebuffer_error(status, NULL); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-04-27 10:22:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-01 17:54:07 +02:00
										 |  |  |   glBindFramebuffer(GL_READ_FRAMEBUFFER, GPU_framebuffer_default()); | 
					
						
							| 
									
										
										
										
											2018-04-27 10:22:37 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const int w = GPU_texture_width(ofs->color); | 
					
						
							|  |  |  |   const int h = GPU_texture_height(ofs->color); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) { | 
					
						
							|  |  |  |     /* For a multi-sample texture,
 | 
					
						
							|  |  |  |      * we need to create an intermediate buffer to blit to, | 
					
						
							|  |  |  |      * before its copied using 'glReadPixels' */ | 
					
						
							|  |  |  |     GLuint fbo_blit = 0; | 
					
						
							|  |  |  |     GLuint tex_blit = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* create texture for new 'fbo_blit' */ | 
					
						
							|  |  |  |     glGenTextures(1, &tex_blit); | 
					
						
							|  |  |  |     glBindTexture(GL_TEXTURE_2D, tex_blit); | 
					
						
							|  |  |  |     glTexImage2D( | 
					
						
							|  |  |  |         GL_TEXTURE_2D, 0, (type == GL_FLOAT) ? GL_RGBA16F : GL_RGBA8, w, h, 0, GL_RGBA, type, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* write into new single-sample buffer */ | 
					
						
							|  |  |  |     glGenFramebuffers(1, &fbo_blit); | 
					
						
							|  |  |  |     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); | 
					
						
							|  |  |  |     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_blit, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); | 
					
						
							|  |  |  |     if (status != GL_FRAMEBUFFER_COMPLETE) { | 
					
						
							|  |  |  |       goto finally; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* perform the copy */ | 
					
						
							|  |  |  |     glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* read the results */ | 
					
						
							|  |  |  |     glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); | 
					
						
							|  |  |  |     glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* restore the original frame-bufer */ | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |     GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); | 
					
						
							|  |  |  |     glBindFramebuffer(GL_FRAMEBUFFER, ofs_fb->object); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   finally: | 
					
						
							|  |  |  |     /* cleanup */ | 
					
						
							|  |  |  |     glDeleteTextures(1, &tex_blit); | 
					
						
							|  |  |  |     glDeleteFramebuffers(1, &fbo_blit); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int GPU_offscreen_width(const GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return GPU_texture_width(ofs->color); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int GPU_offscreen_height(const GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return GPU_texture_height(ofs->color); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 18:18:04 +01:00
										 |  |  | GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return ofs->color; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-03 02:50:29 +10:00
										 |  |  | /* only to be used by viewport code! */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs, | 
					
						
							|  |  |  |                                      GPUFrameBuffer **r_fb, | 
					
						
							|  |  |  |                                      GPUTexture **r_color, | 
					
						
							|  |  |  |                                      GPUTexture **r_depth) | 
					
						
							| 
									
										
										
										
											2017-05-03 02:50:29 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-13 21:31:46 +02:00
										 |  |  |   *r_fb = gpu_offscreen_fb_get(ofs); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   *r_color = ofs->color; | 
					
						
							|  |  |  |   *r_depth = ofs->depth; | 
					
						
							| 
									
										
										
										
											2017-05-09 15:09:39 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-06-26 15:17:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | void GPU_clear_color(float red, float green, float blue, float alpha) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   glClearColor(red, green, blue, alpha); | 
					
						
							| 
									
										
										
										
											2018-06-26 15:17:31 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 20:28:27 +02:00
										 |  |  | void GPU_clear_depth(float depth) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   glClearDepth(depth); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:15:43 +11:00
										 |  |  | void GPU_clear(eGPUFrameBufferBits flags) | 
					
						
							| 
									
										
										
										
											2018-06-26 15:17:31 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   glClear(convert_buffer_bits_to_gl(flags)); | 
					
						
							| 
									
										
										
										
											2018-06-26 15:17:31 -06:00
										 |  |  | } |