| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ***** BEGIN GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is: all of this file. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contributor(s): Brecht Van Lommel. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ***** END GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_blenlib.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-25 03:52:57 +02:00
										 |  |  | #include "BLI_threads.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | #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
										 |  |  | 
 | 
					
						
							|  |  |  | #include "BKE_global.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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"
 | 
					
						
							| 
									
										
										
										
											2017-02-22 19:57:58 +01:00
										 |  |  | #include "GPU_matrix.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | #include "GPU_shader.h"
 | 
					
						
							|  |  |  | #include "GPU_texture.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 03:52:57 +02:00
										 |  |  | static ThreadLocal(GLuint) g_currentfb; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | typedef enum { | 
					
						
							|  |  |  | 	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, | 
					
						
							|  |  |  | 	/* Number of maximum output slots.
 | 
					
						
							|  |  |  | 	 * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */ | 
					
						
							|  |  |  | 	/* 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 | 
					
						
							|  |  |  | } 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 { | 
					
						
							|  |  |  | 	GLuint object; | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	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 accross 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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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 | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	return table[type]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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: | 
					
						
							|  |  |  | 			return GPU_FB_DEPTH_STENCIL_ATTACHMENT; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return GPU_FB_COLOR_ATTACHMENT0 + slot; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 14:18:39 +02:00
										 |  |  | static GLenum convert_buffer_bits_to_gl(GPUFrameBufferBits bits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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 17:46:48 +02:00
										 |  |  | static GPUTexture *framebuffer_get_depth_tex(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex) | 
					
						
							|  |  |  | 		return fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex;; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GPUTexture *framebuffer_get_color_tex(GPUFrameBuffer *fb, int slot) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return fb->attachments[GPU_FB_COLOR_ATTACHMENT0 + slot].tex; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-02-03 16:01:32 +01:00
										 |  |  | 	const char *format = "GPUFrameBuffer: framebuffer status %s\n"; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	const char *err = "unknown"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | #define format_status(X) \
 | 
					
						
							|  |  |  | 	case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	switch (status) { | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | 		/* success */ | 
					
						
							|  |  |  | 		format_status(COMPLETE) | 
					
						
							|  |  |  | 		/* errors shared by OpenGL desktop & ES */ | 
					
						
							|  |  |  | 		format_status(INCOMPLETE_ATTACHMENT) | 
					
						
							|  |  |  | 		format_status(INCOMPLETE_MISSING_ATTACHMENT) | 
					
						
							|  |  |  | 		format_status(UNSUPPORTED) | 
					
						
							|  |  |  | #if 0 /* for OpenGL ES only */
 | 
					
						
							|  |  |  | 		format_status(INCOMPLETE_DIMENSIONS) | 
					
						
							|  |  |  | #else /* for desktop GL only */
 | 
					
						
							|  |  |  | 		format_status(INCOMPLETE_DRAW_BUFFER) | 
					
						
							|  |  |  | 		format_status(INCOMPLETE_READ_BUFFER) | 
					
						
							|  |  |  | 		format_status(INCOMPLETE_MULTISAMPLE) | 
					
						
							|  |  |  | 		format_status(UNDEFINED) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | #undef format_status
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	if (err_out) { | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | 		BLI_snprintf(err_out, 256, format, err); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2016-08-08 18:02:40 -04:00
										 |  |  | 		fprintf(stderr, format, err); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* GPUFrameBuffer */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GPUFrameBuffer *GPU_framebuffer_create(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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");; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static void gpu_framebuffer_init(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-08-04 21:11:45 -04:00
										 |  |  | 	glGenFramebuffers(1, &fb->object); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	/* This restores the framebuffer if it was bound */ | 
					
						
							|  |  |  | 	glDeleteFramebuffers(1, &fb->object); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (g_currentfb == fb->object) { | 
					
						
							|  |  |  | 		g_currentfb = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) { | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 		fprintf(stderr, | 
					
						
							|  |  |  | 		        "Attaching to index %d framebuffer slot unsupported. " | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		        "Use at most %d\n", slot, GPU_FB_MAX_COLOR_ATTACHMENT); | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	GPUAttachmentType type = attachment_type_from_tex(tex, slot); | 
					
						
							|  |  |  | 	GPUAttachment *attachment = &fb->attachments[type]; | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if ((attachment->tex == tex) && | 
					
						
							|  |  |  | 		(attachment->mip == mip) && | 
					
						
							|  |  |  | 		(attachment->layer == layer)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return; /* Exact same texture already bound here. */ | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	else if (attachment->tex != NULL) { | 
					
						
							|  |  |  | 		GPU_framebuffer_texture_detach(fb, attachment->tex); | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (attachment->tex == NULL) { | 
					
						
							|  |  |  | 		GPU_texture_attach_framebuffer(tex, fb, type); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-08 20:12:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	return gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip); | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	/* NOTE: We could support 1D ARRAY texture. */ | 
					
						
							|  |  |  | 	BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY); | 
					
						
							|  |  |  | 	return gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip); | 
					
						
							| 
									
										
										
										
											2017-06-16 13:25:22 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	BLI_assert(GPU_texture_cube(tex)); | 
					
						
							|  |  |  | 	return gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	GPUAttachment *attachment = &fb->attachments[type]; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	attachment->tex = NULL; | 
					
						
							|  |  |  | 	GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_ct) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	int slot = 0; | 
					
						
							|  |  |  | 	for (int i = 1; i < config_ct; ++i, ++slot) { | 
					
						
							|  |  |  | 		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); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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_attachment_detach(GPUAttachment *UNUSED(attachment), GPUAttachmentType attach_type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; | 
					
						
							|  |  |  | 	int numslots = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BLI_assert(g_currentfb == fb->object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Update attachments */ | 
					
						
							|  |  |  | 	for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		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; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 			numslots++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	/* Update draw buffers (color targets)
 | 
					
						
							|  |  |  | 	 * This state is saved in the FBO */ | 
					
						
							|  |  |  | 	if (numslots) | 
					
						
							|  |  |  | 		glDrawBuffers(numslots, gl_attachments); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		glDrawBuffer(GL_NONE); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | void GPU_framebuffer_bind(GPUFrameBuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (fb->object == 0) | 
					
						
							|  |  |  | 		gpu_framebuffer_init(fb); | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (g_currentfb != fb->object) | 
					
						
							|  |  |  | 		glBindFramebuffer(GL_FRAMEBUFFER, fb->object); | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	g_currentfb = fb->object; | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (fb->dirty_flag != 0) | 
					
						
							|  |  |  | 		gpu_framebuffer_update_attachments(fb); | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	/* TODO manually check for errors? */ | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | 	char err_out[256]; | 
					
						
							|  |  |  | 	if (!GPU_framebuffer_check_valid(fb, err_out)) { | 
					
						
							|  |  |  | 		printf("Invalid %s\n", err_out); | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-02-07 11:20:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (fb->multisample) | 
					
						
							| 
									
										
										
										
											2017-09-26 14:01:50 +02:00
										 |  |  | 		glEnable(GL_MULTISAMPLE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (g_currentfb != 0) { | 
					
						
							|  |  |  | 		glBindFramebuffer(GL_FRAMEBUFFER, 0); | 
					
						
							|  |  |  | 		g_currentfb = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	return (fb->object == g_currentfb) && (fb->object != 0); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | unsigned int GPU_framebuffer_current_get(void) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	return g_currentfb; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (g_currentfb != fb->object) | 
					
						
							|  |  |  | 		GPU_framebuffer_bind(fb); | 
					
						
							| 
									
										
										
										
											2018-02-17 14:05:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 00:52:52 -04:00
										 |  |  | 	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 21:11:45 -04:00
										 |  |  | 	if (status != GL_FRAMEBUFFER_COMPLETE) { | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 		GPU_framebuffer_restore(); | 
					
						
							| 
									
										
										
										
											2017-04-12 20:18:44 +10:00
										 |  |  | 		gpu_print_framebuffer_error(status, err_out); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-19 00:52:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) \
 | 
					
						
							|  |  |  | 	BLI_assert(GPU_framebuffer_bound(_fb)); \ | 
					
						
							|  |  |  | 	UNUSED_VARS_NDEBUG(_fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Needs to be done after binding. */ | 
					
						
							|  |  |  | void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	glViewport(x, y, w, h); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_framebuffer_clear( | 
					
						
							|  |  |  |         GPUFrameBuffer *fb, GPUFrameBufferBits buffers, | 
					
						
							|  |  |  |         const float clear_col[4], float clear_depth, unsigned int clear_stencil) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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(clear_stencil); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	GLbitfield mask = convert_buffer_bits_to_gl(buffers); | 
					
						
							|  |  |  | 	glClear(mask); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CHECK_FRAMEBUFFER_IS_BOUND(fb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	GLenum type = GL_DEPTH_COMPONENT; | 
					
						
							|  |  |  | 	glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ | 
					
						
							|  |  |  | 	glReadPixels(x, y, w, h, type, GL_FLOAT, data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_framebuffer_read_color( | 
					
						
							|  |  |  |         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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* read_slot and write_slot are only used for color buffers. */ | 
					
						
							| 
									
										
										
										
											2017-11-10 23:36:05 +01:00
										 |  |  | void GPU_framebuffer_blit( | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  |         GPUFrameBuffer *fb_read, int read_slot, | 
					
						
							|  |  |  |         GPUFrameBuffer *fb_write, int write_slot, | 
					
						
							|  |  |  |         GPUFrameBufferBits blit_buffers) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BLI_assert(blit_buffers != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	GLuint prev_fb = g_currentfb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 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) { | 
					
						
							| 
									
										
										
										
											2017-11-10 23:36:05 +01:00
										 |  |  | 		BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex)); | 
					
						
							| 
									
										
										
										
											2017-11-14 20:49:13 +01:00
										 |  |  | 		BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); | 
					
						
							| 
									
										
										
										
											2017-11-10 23:36:05 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (do_stencil) { | 
					
						
							| 
									
										
										
										
											2017-11-10 23:36:05 +01:00
										 |  |  | 		BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex)); | 
					
						
							| 
									
										
										
										
											2017-11-14 20:49:13 +01:00
										 |  |  | 		BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); | 
					
						
							| 
									
										
										
										
											2017-11-10 23:36:05 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	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)); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-10 23:36:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 15:15:42 +01:00
										 |  |  | 	glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); | 
					
						
							|  |  |  | 	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2017-02-15 15:15:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Restore previous framebuffer */ | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (fb_write->object == prev_fb) { | 
					
						
							|  |  |  | 		GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); | 
					
						
							|  |  |  | 		g_currentfb = prev_fb; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-15 15:15:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Use this if you need to custom downsample your texture and use the previous mip level as input. | 
					
						
							|  |  |  |  * This function only takes care of the correct texture handling. It execute the callback for each texture level. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | void GPU_framebuffer_recursive_downsample( | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  |         GPUFrameBuffer *fb, int max_lvl, | 
					
						
							|  |  |  |         void (*callback)(void *userData, int level), void *userData) | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	/* Framebuffer must be up to date and bound. This simplify this function. */ | 
					
						
							|  |  |  | 	if (g_currentfb != fb->object || fb->dirty_flag != 0 || fb->object == 0) { | 
					
						
							|  |  |  | 		GPU_framebuffer_bind(fb); | 
					
						
							| 
									
										
										
										
											2017-07-21 14:27:16 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	/* HACK: We make the framebuffer appear not bound in order to
 | 
					
						
							|  |  |  | 	 * not trigger any error in GPU_texture_bind().  */ | 
					
						
							|  |  |  | 	GLuint prev_fb = g_currentfb; | 
					
						
							|  |  |  | 	g_currentfb = 0; | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 	int current_dim[2] = {fb->width, fb->height}; | 
					
						
							|  |  |  | 	for (i = 1; i < max_lvl + 1; i++) { | 
					
						
							| 
									
										
										
										
											2017-10-17 03:06:04 +02:00
										 |  |  | 		/* calculate next viewport size */ | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		current_dim[0] = max_ii(current_dim[0] / 2, 1); | 
					
						
							|  |  |  | 		current_dim[1] = max_ii(current_dim[1] / 2, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { | 
					
						
							|  |  |  | 			if (fb->attachments[type].tex != NULL) { | 
					
						
							|  |  |  | 				/* 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, i - 1); | 
					
						
							|  |  |  | 				GPU_texture_unbind(tex); | 
					
						
							|  |  |  | 				/* copy attachment and replace miplevel. */ | 
					
						
							|  |  |  | 				GPUAttachment attachment = fb->attachments[type]; | 
					
						
							|  |  |  | 				attachment.mip = i; | 
					
						
							|  |  |  | 				gpu_framebuffer_attachment_attach(&attachment, type); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-10-10 17:18:29 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		glViewport(0, 0, current_dim[0], current_dim[1]); | 
					
						
							|  |  |  | 		callback(userData, i); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (current_dim[0] == 1 && current_dim[1] == 1) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { | 
					
						
							|  |  |  | 		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); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	g_currentfb = prev_fb; | 
					
						
							| 
									
										
										
										
											2017-06-22 02:01:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | /* GPUOffScreen */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct GPUOffScreen { | 
					
						
							|  |  |  | 	GPUFrameBuffer *fb; | 
					
						
							|  |  |  | 	GPUTexture *color; | 
					
						
							|  |  |  | 	GPUTexture *depth; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 18:18:04 +01: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
										 |  |  | { | 
					
						
							|  |  |  | 	GPUOffScreen *ofs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, | 
					
						
							|  |  |  | 	        (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 18:18:04 +01:00
										 |  |  | 	if (depth) { | 
					
						
							|  |  |  | 		ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (!ofs->depth || !ofs->color) { | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 		GPU_offscreen_free(ofs); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	GPU_framebuffer_ensure_config(&ofs->fb, { | 
					
						
							|  |  |  | 		GPU_ATTACHMENT_TEXTURE(ofs->depth), | 
					
						
							|  |  |  | 		GPU_ATTACHMENT_TEXTURE(ofs->color) | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	/* check validity at the very end! */ | 
					
						
							|  |  |  | 	if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { | 
					
						
							|  |  |  | 		GPU_offscreen_free(ofs); | 
					
						
							|  |  |  | 		return NULL;		 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	GPU_framebuffer_restore(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ofs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_offscreen_free(GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ofs->fb) | 
					
						
							|  |  |  | 		GPU_framebuffer_free(ofs->fb); | 
					
						
							|  |  |  | 	if (ofs->color) | 
					
						
							|  |  |  | 		GPU_texture_free(ofs->color); | 
					
						
							|  |  |  | 	if (ofs->depth) | 
					
						
							|  |  |  | 		GPU_texture_free(ofs->depth); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	MEM_freeN(ofs); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (save) { | 
					
						
							|  |  |  | 		gpuPushAttrib(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	glDisable(GL_SCISSOR_TEST); | 
					
						
							|  |  |  | 	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
										 |  |  | { | 
					
						
							|  |  |  | 	GPU_framebuffer_restore(); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	if (restore) { | 
					
						
							|  |  |  | 		gpuPopAttrib(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const int w = GPU_texture_width(ofs->color); | 
					
						
							|  |  |  | 	const int h = GPU_texture_height(ofs->color); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 	BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		glTexImage2D(GL_TEXTURE_2D, 0, (type == GL_FLOAT) ? GL_RGBA16F : GL_RGBA8, | 
					
						
							|  |  |  | 		             w, h, 0, GL_RGBA, type, 0); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* write into new single-sample buffer */ | 
					
						
							| 
									
										
										
										
											2016-08-04 21:11:45 -04:00
										 |  |  | 		glGenFramebuffers(1, &fbo_blit); | 
					
						
							|  |  |  | 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 
					
						
							|  |  |  | 		                       GL_TEXTURE_2D, tex_blit, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); | 
					
						
							| 
									
										
										
										
											2016-08-04 21:11:45 -04:00
										 |  |  | 		if (status != GL_FRAMEBUFFER_COMPLETE) { | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 			goto finally; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* perform the copy */ | 
					
						
							| 
									
										
										
										
											2016-08-04 21:11:45 -04:00
										 |  |  | 		glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* read the results */ | 
					
						
							| 
									
										
										
										
											2016-08-04 21:11:45 -04:00
										 |  |  | 		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 		glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* restore the original frame-bufer */ | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		glBindFramebuffer(GL_FRAMEBUFFER, ofs->fb->object); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							|  |  |  | 		/* cleanup */ | 
					
						
							| 
									
										
										
										
											2018-03-25 17:46:48 +02:00
										 |  |  | 		glDeleteTextures(1, &tex_blit); | 
					
						
							|  |  |  | 		glDeleteFramebuffers(1, &fbo_blit); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int GPU_offscreen_width(const GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return GPU_texture_width(ofs->color); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int GPU_offscreen_height(const GPUOffScreen *ofs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return GPU_texture_height(ofs->color); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 18:18:04 +01:00
										 |  |  | GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs) | 
					
						
							| 
									
										
										
										
											2015-12-06 21:20:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-13 18:18:04 +01: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! */ | 
					
						
							|  |  |  | void GPU_offscreen_viewport_data_get( | 
					
						
							|  |  |  |         GPUOffScreen *ofs, | 
					
						
							|  |  |  |         GPUFrameBuffer **r_fb, GPUTexture **r_color, GPUTexture **r_depth) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	*r_fb = ofs->fb; | 
					
						
							|  |  |  | 	*r_color = ofs->color; | 
					
						
							|  |  |  | 	*r_depth = ofs->depth; | 
					
						
							| 
									
										
										
										
											2017-05-09 15:09:39 +02:00
										 |  |  | } |