[Bf-blender-cvs] [2d084d4ec43] blender2.8: GPU: Fix Issue with recursive downsample and Intel HDXXX

Clément Foucault noreply at git.blender.org
Mon Oct 22 13:03:30 CEST 2018


Commit: 2d084d4ec430ec8b280a52286eeeca770f2221bc
Author: Clément Foucault
Date:   Mon Oct 22 12:58:11 2018 +0200
Branches: blender2.8
https://developer.blender.org/rB2d084d4ec430ec8b280a52286eeeca770f2221bc

GPU: Fix Issue with recursive downsample and Intel HDXXX

This is caused by a driver bug that prevent us from rendering to (or even
binding) a texture mip level that is below GL_TEXTURE_MAX_LEVEL of the
target texture. This is fine in most drivers (and legal AFAIK) but not on
thoses Intels HDXXX + Windows.

As a fix we just put GL_TEXTURE_MAX_LEVEL lower (which is illegal because
it is undefined behaviour), but in practice it works ok and does not
trigger any warnings or errors.

This commit fixes most of the problems encountered on these GPUs (T56668).

===================================================================

M	source/blender/gpu/GPU_extensions.h
M	source/blender/gpu/intern/gpu_extensions.c
M	source/blender/gpu/intern/gpu_framebuffer.c
M	source/blender/gpu/intern/gpu_texture.c

===================================================================

diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 1059ba06953..994f545eb38 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -51,6 +51,7 @@ int GPU_max_ubo_binds(void);
 int GPU_max_ubo_size(void);
 int GPU_color_depth(void);
 void GPU_get_dfdy_factors(float fac[2]);
+bool GPU_mip_render_workaround(void);
 
 bool GPU_mem_stats_supported(void);
 void GPU_mem_stats_get(int *totalmem, int *freemem);
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 198f986d06e..c95f5e5e252 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -37,8 +37,10 @@
 #include "BLI_math_vector.h"
 
 #include "BKE_global.h"
+#include "MEM_guardedalloc.h"
 
 #include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
 #include "GPU_glew.h"
 #include "GPU_texture.h"
 
@@ -83,8 +85,42 @@ static struct GPUGlobal {
 	 * number is factor on screen and second is off-screen */
 	float dfdyfactors[2];
 	float max_anisotropy;
+	/* Some Intel drivers have issues with using mips as framebuffer targets if
+	 * GL_TEXTURE_MAX_LEVEL is higher than the target mip.
+	 * We need a workaround in this cases. */
+	bool mip_render_workaround;
 } GG = {1, 0};
 
+
+static void gpu_detect_mip_render_workaround(void)
+{
+	int cube_size = 2;
+	float *source_pix = MEM_callocN(sizeof(float) * 4 * 6 * cube_size * cube_size, __func__);
+	float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f};
+
+	GPUTexture *tex = GPU_texture_create_cube(cube_size, GPU_RGBA16F, source_pix, NULL);
+	MEM_freeN(source_pix);
+
+	GPU_texture_bind(tex, 0);
+	GPU_texture_generate_mipmap(tex);
+	glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
+	glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, 0);
+	GPU_texture_unbind(tex);
+
+	GPUFrameBuffer *fb = GPU_framebuffer_create();
+	GPU_framebuffer_texture_attach(fb, tex, 0, 1);
+	GPU_framebuffer_bind(fb);
+	GPU_framebuffer_clear_color(fb, clear_color);
+	GPU_framebuffer_restore();
+	GPU_framebuffer_free(fb);
+
+	float *data = GPU_texture_read(tex, GPU_DATA_FLOAT, 1);
+	GG.mip_render_workaround = !equals_v4v4(clear_color, data);
+
+	MEM_freeN(data);
+	GPU_texture_free(tex);
+}
+
 /* GPU Types */
 
 bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
@@ -154,6 +190,11 @@ void GPU_get_dfdy_factors(float fac[2])
 	copy_v2_v2(fac, GG.dfdyfactors);
 }
 
+bool GPU_mip_render_workaround(void)
+{
+	return GG.mip_render_workaround;
+}
+
 void gpu_extensions_init(void)
 {
 	/* during 2.8 development each platform has its own OpenGL minimum requirements
@@ -253,6 +294,7 @@ void gpu_extensions_init(void)
 	GG.os = GPU_OS_UNIX;
 #endif
 
+	gpu_detect_mip_render_workaround();
 
 	/* df/dy calculation factors, those are dependent on driver */
 	if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 346d1320b75..7329eee44b0 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -640,11 +640,15 @@ void GPU_framebuffer_recursive_downsample(
 
 		for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
 			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, 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];
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 6a8e686afb3..c3a1148a360 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -916,12 +916,13 @@ GPUTexture *GPU_texture_create_cube(
 	const int channels = gpu_get_component_count(tex_format);
 
 	if (fpixels) {
-		fpixels_px = fpixels + 0 * w * w * channels;
-		fpixels_nx = fpixels + 1 * w * w * channels;
-		fpixels_py = fpixels + 2 * w * w * channels;
-		fpixels_ny = fpixels + 3 * w * w * channels;
-		fpixels_pz = fpixels + 4 * w * w * channels;
-		fpixels_nz = fpixels + 5 * w * w * channels;
+		int face_ofs = w * w * channels;
+		fpixels_px = fpixels + 0 * face_ofs;
+		fpixels_nx = fpixels + 1 * face_ofs;
+		fpixels_py = fpixels + 2 * face_ofs;
+		fpixels_ny = fpixels + 3 * face_ofs;
+		fpixels_pz = fpixels + 4 * face_ofs;
+		fpixels_nz = fpixels + 5 * face_ofs;
 	}
 	else {
 		fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL;
@@ -1099,6 +1100,7 @@ void *GPU_texture_read(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplv
 	samples_count *= size[0];
 	samples_count *= max_ii(1, size[1]);
 	samples_count *= max_ii(1, size[2]);
+	samples_count *= (GPU_texture_cube(tex)) ? 6 : 1;
 
 	switch (gpu_data_format) {
 		case GPU_DATA_FLOAT:
@@ -1123,7 +1125,16 @@ void *GPU_texture_read(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplv
 
 	glBindTexture(tex->target, tex->bindcode);
 
-	glGetTexImage(tex->target, miplvl, data_format, data_type, buf);
+	if (GPU_texture_cube(tex)) {
+		int cube_face_size = buf_size / 6;
+		for (int i = 0; i < 6; ++i) {
+			glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplvl, data_format, data_type,
+			              ((char *)buf) + cube_face_size * i);
+		}
+	}
+	else {
+		glGetTexImage(tex->target, miplvl, data_format, data_type, buf);
+	}
 
 	glBindTexture(tex->target, 0);



More information about the Bf-blender-cvs mailing list