[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [48425] trunk/blender/source: Finally committing support for compressed textures on the GPU (DDS+DXT).

Mitchell Stokes mogurijin at gmail.com
Sat Jun 30 06:34:36 CEST 2012


Revision: 48425
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=48425
Author:   moguri
Date:     2012-06-30 04:34:34 +0000 (Sat, 30 Jun 2012)
Log Message:
-----------
Finally committing support for compressed textures on the GPU (DDS+DXT). This patch started out as a patch by me, then cleaned up by Kupoman during his work on Cucumber.

One important thing to keep in mind when using this feature is that you'll need to flip your textures vertically (both the GIMP and Photoshop DDS tools I've seen have support for this on export). This is a quirk in using a texture format originally made for DirectX/DirectDraw, and flipping the compressed data is a real headache. Another quick fix for this issue is to change the Y value for the Size in the Mapping panel in the Texture properties to -1 (default is 1).

Modified Paths:
--------------
    trunk/blender/source/blender/gpu/CMakeLists.txt
    trunk/blender/source/blender/gpu/GPU_draw.h
    trunk/blender/source/blender/gpu/SConscript
    trunk/blender/source/blender/gpu/intern/gpu_draw.c
    trunk/blender/source/blender/imbuf/IMB_imbuf_types.h
    trunk/blender/source/blender/imbuf/intern/allocimbuf.c
    trunk/blender/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
    trunk/blender/source/blender/imbuf/intern/dds/DirectDrawSurface.h
    trunk/blender/source/blender/imbuf/intern/dds/dds_api.cpp
    trunk/blender/source/gameengine/Ketsji/BL_Texture.cpp
    trunk/blender/source/gameengine/Ketsji/BL_Texture.h
    trunk/blender/source/gameengine/Ketsji/CMakeLists.txt

Modified: trunk/blender/source/blender/gpu/CMakeLists.txt
===================================================================
--- trunk/blender/source/blender/gpu/CMakeLists.txt	2012-06-30 04:29:16 UTC (rev 48424)
+++ trunk/blender/source/blender/gpu/CMakeLists.txt	2012-06-30 04:34:34 UTC (rev 48425)
@@ -71,5 +71,10 @@
 
 add_definitions(-DGLEW_STATIC)
 
+if(WITH_IMAGE_DDS)
+	add_definitions(-DWITH_DDS)
+endif()
+
+
 blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}")
 

Modified: trunk/blender/source/blender/gpu/GPU_draw.h
===================================================================
--- trunk/blender/source/blender/gpu/GPU_draw.h	2012-06-30 04:29:16 UTC (rev 48424)
+++ trunk/blender/source/blender/gpu/GPU_draw.h	2012-06-30 04:34:34 UTC (rev 48425)
@@ -122,6 +122,9 @@
 void GPU_update_images_framechange(void);
 int GPU_update_image_time(struct Image *ima, double time);
 int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, int compare, int mipmap);
+void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int rectw, int recth, int mipmap, int use_hight_bit_depth, struct Image *ima);
+void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, struct Image *ima, struct ImBuf *ibuf);
+int GPU_upload_dxt_texture(struct ImBuf *ibuf);
 void GPU_free_image(struct Image *ima);
 void GPU_free_images(void);
 void GPU_free_images_anim(void);

Modified: trunk/blender/source/blender/gpu/SConscript
===================================================================
--- trunk/blender/source/blender/gpu/SConscript	2012-06-30 04:29:16 UTC (rev 48424)
+++ trunk/blender/source/blender/gpu/SConscript	2012-06-30 04:34:34 UTC (rev 48425)
@@ -17,4 +17,7 @@
 if env['WITH_BF_SMOKE']:
     defs.append('WITH_SMOKE')
 
+if env['WITH_BF_DDS']:
+	defs.append('WITH_DDS')
+
 env.BlenderLib ( 'bf_gpu', sources, Split(incs), defines = defs, libtype=['core','player'], priority=[160,110] )

Modified: trunk/blender/source/blender/gpu/intern/gpu_draw.c
===================================================================
--- trunk/blender/source/blender/gpu/intern/gpu_draw.c	2012-06-30 04:29:16 UTC (rev 48424)
+++ trunk/blender/source/blender/gpu/intern/gpu_draw.c	2012-06-30 04:34:34 UTC (rev 48425)
@@ -427,8 +427,8 @@
 	ImBuf *ibuf = NULL;
 	unsigned int *bind = NULL;
 	int rectw, recth, tpx=0, tpy=0, y;
-	unsigned int *tilerect= NULL, *scalerect= NULL, *rect= NULL;
-	float *ftilerect= NULL, *fscalerect = NULL, *frect = NULL;
+	unsigned int *tilerect= NULL, *rect= NULL;
+	float *ftilerect= NULL, *frect = NULL;
 	float *srgb_frect = NULL;
 	short texwindx, texwindy, texwinsx, texwinsy;
 	/* flag to determine whether high resolution format is used */
@@ -611,7 +611,32 @@
 			rect= tilerect;
 		}
 	}
+#ifdef WITH_DDS
+	if (ibuf->ftype & DDS)
+		GPU_create_gl_tex_compressed(bind, rect, rectw, recth, mipmap, ima, ibuf);
+	else
+#endif
+		GPU_create_gl_tex(bind, rect, frect, rectw, recth, mipmap, use_high_bit_depth, ima);
 
+	/* clean up */
+	if (tilerect)
+		MEM_freeN(tilerect);
+	if (ftilerect)
+		MEM_freeN(ftilerect);
+	if (srgb_frect)
+		MEM_freeN(srgb_frect);
+
+	return *bind;
+}
+
+void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float * frect, int rectw, int recth, int mipmap, int use_high_bit_depth, Image *ima)
+{
+	unsigned int *scalerect = NULL;
+    float *fscalerect = NULL;
+    
+    int tpx = rectw;
+    int tpy = recth;
+    
 	/* scale if not a power of two. this is not strictly necessary for newer 
 	 * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures */
 	if (!is_pow2_limit(rectw) || !is_pow2_limit(recth)) {
@@ -626,9 +651,9 @@
 		}
 		else {
 			scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
-			gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
+			gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, pix, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
 
-			rect= scalerect;
+			pix= scalerect;
 		}
 	}
 
@@ -640,7 +665,7 @@
 		if (use_high_bit_depth)
 			glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA16,  rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
 		else
-			glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+			glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
 	}
@@ -649,14 +674,14 @@
 			if (use_high_bit_depth)
 				glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA16,  rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
 			else
-				glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+				glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
 
 			glGenerateMipmapEXT(GL_TEXTURE_2D);
 		} else {
 			if (use_high_bit_depth)
 				gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA16, rectw, recth, GL_RGBA, GL_FLOAT, frect);
 			else
-				gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+				gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, pix);
 		}
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
@@ -668,21 +693,84 @@
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
 	/* set to modulate with vertex color */
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		
-	/* clean up */
-	if (tilerect)
-		MEM_freeN(tilerect);
-	if (ftilerect)
-		MEM_freeN(ftilerect);
+
 	if (scalerect)
 		MEM_freeN(scalerect);
 	if (fscalerect)
 		MEM_freeN(fscalerect);
-	if (srgb_frect)
-		MEM_freeN(srgb_frect);
-	return *bind;
 }
 
+/**
+ * GPU_upload_dxt_texture() assumes that the texture is already bound and ready to go.
+ * This is so the viewport and the BGE can share some code.
+ * Returns 0 if the provided ImBuf doesn't have a supported DXT compression format
+ */
+int GPU_upload_dxt_texture(ImBuf *ibuf)
+{
+	GLint format, err;
+	int blocksize, height, width, i, size, offset = 0;
+
+	height = ibuf->x;
+	width = ibuf->y;	
+	
+	if (ibuf->dds_data.fourcc == FOURCC_DXT1)
+		format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+	else if (ibuf->dds_data.fourcc == FOURCC_DXT3)
+		format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+	else if (ibuf->dds_data.fourcc == FOURCC_DXT5)
+		format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+	else {
+		printf("Unable to find a suitable DXT compression, falling back to uncompressed\n");
+		return 0;
+	}
+
+	blocksize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
+	for (i=0; i<ibuf->dds_data.nummipmaps && (width||height); ++i) {
+		if (width == 0)
+			width = 1;
+		if (height == 0)
+			height = 1;
+
+		size = ((width+3)/4)*((height+3)/4)*blocksize;
+
+		glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
+			0, size, ibuf->dds_data.data + offset);
+
+		err = glGetError();
+
+		if (err != GL_NO_ERROR)
+			printf("OpenGL error: %s\nFormat: %x\n", gluErrorString(err), format);
+
+		offset += size;
+		width >>= 1;
+		height >>= 1;
+	}
+
+	return 1;
+}
+
+void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, Image *ima, ImBuf *ibuf)
+{
+#ifndef WITH_DDS
+	// Fall back to uncompressed if DDS isn't enabled
+	GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
+#else
+
+
+	glGenTextures(1, (GLuint *)bind);
+	glBindTexture(GL_TEXTURE_2D, *bind);
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	if (GPU_upload_dxt_texture(ibuf) == 0) {
+		glDeleteTextures(1, (GLuint*)bind);
+		GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
+	}
+#endif
+}
 static void gpu_verify_repeat(Image *ima)
 {
 	/* set either clamp or repeat in X/Y */

Modified: trunk/blender/source/blender/imbuf/IMB_imbuf_types.h
===================================================================
--- trunk/blender/source/blender/imbuf/IMB_imbuf_types.h	2012-06-30 04:29:16 UTC (rev 48424)
+++ trunk/blender/source/blender/imbuf/IMB_imbuf_types.h	2012-06-30 04:34:34 UTC (rev 48425)
@@ -50,6 +50,13 @@
 #define IB_MIPMAP_LEVELS	20
 #define IB_FILENAME_SIZE	1024
 
+typedef struct DDSData {
+	unsigned int fourcc; /* DDS fourcc info */
+	unsigned int nummipmaps; /* The number of mipmaps in the dds file */
+	unsigned char *data; /* The compressed image data */
+	unsigned int size; /* The size of the compressed data */
+} DDSData;
+
 /**
  * \ingroup imbuf
  * This is the abstraction of an image.  ImBuf is the basic type used for all
@@ -119,6 +126,9 @@
 	unsigned char *encodedbuffer;     /* Compressed image only used with png currently */
 	unsigned int   encodedsize;       /* Size of data written to encodedbuffer */
 	unsigned int   encodedbuffersize; /* Size of encodedbuffer */
+
+	/* information for compressed textures */
+	struct DDSData dds_data;
 } ImBuf;
 
 /* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */
@@ -215,6 +225,28 @@
 #define IB_PROFILE_SRGB			2
 #define IB_PROFILE_CUSTOM		3
 
+/* dds */
+#ifdef WITH_DDS
+#ifndef MAKEFOURCC
+#define MAKEFOURCC(ch0, ch1, ch2, ch3)\
+	((unsigned long)(unsigned char)(ch0) | \
+	((unsigned long)(unsigned char)(ch1) << 8) | \
+	((unsigned long)(unsigned char)(ch2) << 16) | \
+	((unsigned long)(unsigned char)(ch3) << 24))
+#endif //MAKEFOURCC
+
+/*
+ * FOURCC codes for DX compressed-texture pixel formats
+ */
+
+#define FOURCC_DDS   (MAKEFOURCC('D','D','S',' '))
+#define FOURCC_DXT1  (MAKEFOURCC('D','X','T','1'))
+#define FOURCC_DXT2  (MAKEFOURCC('D','X','T','2'))
+#define FOURCC_DXT3  (MAKEFOURCC('D','X','T','3'))
+#define FOURCC_DXT4  (MAKEFOURCC('D','X','T','4'))
+#define FOURCC_DXT5  (MAKEFOURCC('D','X','T','5'))
+
+#endif // DDS
 extern const char *imb_ext_image[];
 extern const char *imb_ext_image_qt[];
 extern const char *imb_ext_movie[];

Modified: trunk/blender/source/blender/imbuf/intern/allocimbuf.c
===================================================================
--- trunk/blender/source/blender/imbuf/intern/allocimbuf.c	2012-06-30 04:29:16 UTC (rev 48424)
+++ trunk/blender/source/blender/imbuf/intern/allocimbuf.c	2012-06-30 04:34:34 UTC (rev 48425)
@@ -162,6 +162,8 @@

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list