From 7b32112df404f482b86c36101e7a6bb73775e986 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Fri, 7 Aug 2015 22:22:14 +0200 Subject: [PATCH 1/3] Make cubemaps work --- hw/xbox/nv2a.c | 199 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 155 insertions(+), 44 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 34917a0fd1..1fab274d59 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -551,6 +551,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) #define NV_PGRAPH_TEXFILTER3 0x00001A00 #define NV_PGRAPH_TEXFMT0 0x00001A04 # define NV_PGRAPH_TEXFMT0_CONTEXT_DMA (1 << 1) +# define NV_PGRAPH_TEXFMT0_CUBEMAPENABLE (1 << 2) # define NV_PGRAPH_TEXFMT0_DIMENSIONALITY 0x000000C0 # define NV_PGRAPH_TEXFMT0_COLOR 0x00007F00 # define NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS 0x000F0000 @@ -952,6 +953,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...) # define NV097_SET_TEXTURE_OFFSET 0x00971B00 # define NV097_SET_TEXTURE_FORMAT 0x00971B04 # define NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA 0x00000003 +# define NV097_SET_TEXTURE_FORMAT_CUBEMAP_ENABLE (1 << 2) # define NV097_SET_TEXTURE_FORMAT_DIMENSIONALITY 0x000000F0 # define NV097_SET_TEXTURE_FORMAT_COLOR 0x0000FF00 # define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_Y8 0x00 @@ -1428,10 +1430,11 @@ typedef struct SurfaceShape { } SurfaceShape; typedef struct TextureShape { + bool cubemap; unsigned int dimensionality; unsigned int color_format; unsigned int levels; - unsigned int width, height; + unsigned int width, height, depth; unsigned int min_mipmap_level, max_mipmap_level; unsigned int pitch; @@ -2152,36 +2155,21 @@ static uint8_t* convert_texture_data(const TextureShape s, } } -static TextureBinding* generate_texture(const TextureShape s, - const uint8_t *texture_data, - const uint8_t *palette_data) +void pgraph_upload_gl_texture(GLenum gl_target, + const TextureShape s, + const uint8_t *texture_data, + const uint8_t *palette_data) { ColorFormatInfo f = kelvin_color_format_map[s.color_format]; - /* Create a new opengl texture */ - GLuint gl_texture; - glGenTextures(1, &gl_texture); - - GLenum gl_target; - if (f.linear) { - /* linear textures use unnormalised texcoords. - * GL_TEXTURE_RECTANGLE_ARB conveniently also does, but - * does not allow repeat and mirror wrap modes. - * (or mipmapping, but xbox d3d says 'Non swizzled and non - * compressed textures cannot be mip mapped.') - * Not sure if that'll be an issue. */ - gl_target = GL_TEXTURE_RECTANGLE; - } else { - gl_target = GL_TEXTURE_2D; - } - - glBindTexture(gl_target, gl_texture); - - NV2A_GL_DLABEL(GL_TEXTURE, gl_texture, - "format: 0x%02X%s, width: %d", - s.color_format, f.linear ? "" : " (SZ)", s.width); - - if (f.linear) { + switch(gl_target) { + case GL_TEXTURE_1D: + assert(false); + break; + case GL_TEXTURE_3D: + assert(false); + break; + case GL_TEXTURE_RECTANGLE: { /* Can't handle strides unaligned to pixels */ assert(s.pitch % f.bytes_per_pixel == 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, @@ -2201,12 +2189,15 @@ static TextureBinding* generate_texture(const TextureShape s, } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } else { - - glTexParameteri(gl_target, GL_TEXTURE_BASE_LEVEL, - s.min_mipmap_level); - glTexParameteri(gl_target, GL_TEXTURE_MAX_LEVEL, - s.levels-1); + break; + } + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { unsigned int width = s.width, height = s.height; @@ -2257,6 +2248,96 @@ static TextureBinding* generate_texture(const TextureShape s, width /= 2; height /= 2; } + + break; + } + default: + assert(false); + break; + } +} + +static TextureBinding* generate_texture(const TextureShape s, + const uint8_t *texture_data, + const uint8_t *palette_data) +{ + ColorFormatInfo f = kelvin_color_format_map[s.color_format]; + + /* Create a new opengl texture */ + GLuint gl_texture; + glGenTextures(1, &gl_texture); + + GLenum gl_target; + if (s.cubemap) { + assert(f.linear == false); + assert(s.dimensionality == 2); + gl_target = GL_TEXTURE_CUBE_MAP; + } else { + if (f.linear) { + /* linear textures use unnormalised texcoords. + * GL_TEXTURE_RECTANGLE_ARB conveniently also does, but + * does not allow repeat and mirror wrap modes. + * (or mipmapping, but xbox d3d says 'Non swizzled and non + * compressed textures cannot be mip mapped.') + * Not sure if that'll be an issue. */ + + /* FIXME: GLSL 330 provides us with textureSize()! Use that? */ + gl_target = GL_TEXTURE_RECTANGLE; + assert(s.dimensionality == 2); + } else { + switch(s.dimensionality) { + case 1: gl_target = GL_TEXTURE_1D; break; + case 2: gl_target = GL_TEXTURE_2D; break; + case 3: gl_target = GL_TEXTURE_3D; break; + default: + assert(false); + break; + } + } + } + + glBindTexture(gl_target, gl_texture); + + NV2A_GL_DLABEL(GL_TEXTURE, gl_texture, + "format: 0x%02X%s, %d dimensions%s, width: %d, height: %d, depth: %d", + s.color_format, f.linear ? "" : " (SZ)", + s.dimensionality, s.cubemap ? " (Cubemap)" : "", + s.width, s.height, s.depth); + + if (gl_target == GL_TEXTURE_CUBE_MAP) { + + size_t length = 0; + unsigned int w = s.width, h = s.height; + int level; + for (level = 0; level < s.levels; level++) { + /* FIXME: This is wrong for compressed textures and textures with 1x? non-square mipmaps */ + length += w * h * f.bytes_per_pixel; + w /= 2; + h /= 2; + } + + pgraph_upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_X, + s, texture_data + 0 * length, palette_data); + pgraph_upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + s, texture_data + 1 * length, palette_data); + pgraph_upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + s, texture_data + 2 * length, palette_data); + pgraph_upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + s, texture_data + 3 * length, palette_data); + pgraph_upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + s, texture_data + 4 * length, palette_data); + pgraph_upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + s, texture_data + 5 * length, palette_data); + } else { + pgraph_upload_gl_texture(gl_target, s, texture_data, palette_data); + } + + /* Linear textures don't support mipmapping */ + if (!f.linear) { + glTexParameteri(gl_target, GL_TEXTURE_BASE_LEVEL, + s.min_mipmap_level); + glTexParameteri(gl_target, GL_TEXTURE_MAX_LEVEL, + s.levels - 1); } if (f.gl_swizzle_mask[0] != 0 || f.gl_swizzle_mask[1] != 0 @@ -2336,12 +2417,15 @@ static void pgraph_bind_textures(NV2AState *d) unsigned int dma_select = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CONTEXT_DMA); + bool cubemap = + GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CUBEMAPENABLE); unsigned int dimensionality = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_DIMENSIONALITY); unsigned int color_format = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_COLOR); unsigned int levels = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS); unsigned int log_width = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_BASE_SIZE_U); unsigned int log_height = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_BASE_SIZE_V); + unsigned int log_depth = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_BASE_SIZE_P); unsigned int rect_width = GET_MASK(pg->regs[NV_PGRAPH_TEXIMAGERECT0 + i*4], @@ -2386,8 +2470,11 @@ static void pgraph_bind_textures(NV2AState *d) glActiveTexture(GL_TEXTURE0 + i); if (!enabled) { - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glBindTexture(GL_TEXTURE_RECTANGLE, 0); + glBindTexture(GL_TEXTURE_1D, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_3D, 0); continue; } @@ -2397,12 +2484,13 @@ static void pgraph_bind_textures(NV2AState *d) continue; } - NV2A_DPRINTF(" texture %d is format 0x%x, (r %d, %d or %d, %d; %d)," + NV2A_DPRINTF(" texture %d is format 0x%x, (r %d, %d or %d, %d, %d; %d%s)," " filter %x %x, levels %d-%d %d bias %d\n", i, color_format, rect_width, rect_height, - 1 << log_width, 1 << log_height, + 1 << log_width, 1 << log_height, 1 << log_depth, pitch, + cubemap ? "; cubemap" : "", min_filter, mag_filter, min_mipmap_level, max_mipmap_level, levels, lod_bias); @@ -2411,13 +2499,16 @@ static void pgraph_bind_textures(NV2AState *d) ColorFormatInfo f = kelvin_color_format_map[color_format]; assert(f.bytes_per_pixel != 0); - unsigned int width, height; + unsigned int width, height, depth; if (f.linear) { + assert(dimensionality == 2); width = rect_width; height = rect_height; + depth = 1; } else { width = 1 << log_width; height = 1 << log_height; + depth = 1 << log_depth; if (max_mipmap_level < levels) { levels = max_mipmap_level; @@ -2448,23 +2539,37 @@ static void pgraph_bind_textures(NV2AState *d) size_t length = 0; if (f.linear) { + assert(cubemap == false); + assert(dimensionality == 2); length = height * pitch; } else { - unsigned int w = width, h = height; - int level; - for (level = 0; level < levels; level++) { - length += w * h * f.bytes_per_pixel; - w /= 2; - h /= 2; + if (dimensionality >= 2) { + unsigned int w = width, h = height; + int level; + for (level = 0; level < levels; level++) { + /* FIXME: This is wrong for compressed textures and textures with 1x? non-square mipmaps */ + length += w * h * f.bytes_per_pixel; + w /= 2; + h /= 2; + } + if (cubemap) { + assert(dimensionality == 2); + length *= 6; + } + if (dimensionality >= 3) { + length *= depth; + } } } TextureShape state = { + .cubemap = cubemap, .dimensionality = dimensionality, .color_format = color_format, .levels = levels, .width = width, .height = height, + .depth = depth, .min_mipmap_level = min_mipmap_level, .max_mipmap_level = max_mipmap_level, .pitch = pitch, @@ -5060,6 +5165,8 @@ static void pgraph_method(NV2AState *d, bool dma_select = GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA) == 2; + bool cubemap = + GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CUBEMAP_ENABLE); unsigned int dimensionality = GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_DIMENSIONALITY); unsigned int color_format = @@ -5070,14 +5177,18 @@ static void pgraph_method(NV2AState *d, GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_U); unsigned int log_height = GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_V); + unsigned int log_depth = + GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_P); uint32_t *reg = &pg->regs[NV_PGRAPH_TEXFMT0 + slot * 4]; SET_MASK(*reg, NV_PGRAPH_TEXFMT0_CONTEXT_DMA, dma_select); + SET_MASK(*reg, NV_PGRAPH_TEXFMT0_CUBEMAPENABLE, cubemap); SET_MASK(*reg, NV_PGRAPH_TEXFMT0_DIMENSIONALITY, dimensionality); SET_MASK(*reg, NV_PGRAPH_TEXFMT0_COLOR, color_format); SET_MASK(*reg, NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS, levels); SET_MASK(*reg, NV_PGRAPH_TEXFMT0_BASE_SIZE_U, log_width); SET_MASK(*reg, NV_PGRAPH_TEXFMT0_BASE_SIZE_V, log_height); + SET_MASK(*reg, NV_PGRAPH_TEXFMT0_BASE_SIZE_P, log_height); pg->texture_dirty[slot] = true; break; From c96d32e55316363a73f75229231640dbc2642f62 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Aug 2015 01:49:47 +0200 Subject: [PATCH 2/3] New swizzle functions --- hw/xbox/swizzle.c | 166 ++++++++++++++++++++++++++++++---------------- hw/xbox/swizzle.h | 38 ++++++++--- 2 files changed, 139 insertions(+), 65 deletions(-) diff --git a/hw/xbox/swizzle.c b/hw/xbox/swizzle.c index d9c58ccd2d..b5700ba355 100644 --- a/hw/xbox/swizzle.c +++ b/hw/xbox/swizzle.c @@ -22,71 +22,122 @@ #include #include +#include #include "qemu/osdep.h" #include "hw/xbox/swizzle.h" -static unsigned int log2i(unsigned int i) +/* This should be pretty straightforward. + * It creates a bit pattern like ..zyxzyxzyx from ..xxx, ..yyy and ..zzz + * If there are no bits left from any component it will pack the other masks + * more tighly (Example: zzxzxzyx = Fewer x than z and even fewer y) + */ +static void generate_swizzle_masks(unsigned int width, + unsigned int height, + unsigned int depth, + uint32_t* mask_x, + uint32_t* mask_y, + uint32_t* mask_z) { - unsigned int r = 0; - while (i >>= 1) r++; - return r; + uint32_t x = 0, y = 0, z = 0; + uint32_t bit = 1; + uint32_t mask_bit = 1; + bool done; + do { + done = true; + if (bit < width) { x |= mask_bit; mask_bit <<= 1; done = false; } + if (bit < height) { y |= mask_bit; mask_bit <<= 1; done = false; } + if (bit < depth) { z |= mask_bit; mask_bit <<= 1; done = false; } + bit <<= 1; + } while(!done); + assert(x ^ y ^ z == (mask_bit - 1)); + *mask_x = x; + *mask_y = y; + *mask_z = z; +} + +/* This fills a pattern with a value if your value has bits abcd and your + * pattern is 11010100100 this will return: 0a0b0c00d00 + */ +static uint32_t fill_pattern(uint32_t pattern, uint32_t value) +{ + uint32_t result = 0; + uint32_t bit = 1; + while(value) { + if (pattern & bit) { + /* Copy bit to result */ + result |= value & 1 ? bit : 0; + value >>= 1; + } + bit <<= 1; + } + return result; } static unsigned int get_swizzled_offset( - unsigned int x, unsigned int y, - unsigned int width, unsigned int height, + unsigned int x, unsigned int y, unsigned int z, + uint32_t mask_x, uint32_t mask_y, uint32_t mask_z, unsigned int bytes_per_pixel) { - unsigned int k = log2i(MIN(width, height)); - - unsigned int u = (x & 0x001) << 0 | - (x & 0x002) << 1 | - (x & 0x004) << 2 | - (x & 0x008) << 3 | - (x & 0x010) << 4 | - (x & 0x020) << 5 | - (x & 0x040) << 6 | - (x & 0x080) << 7 | - (x & 0x100) << 8 | - (x & 0x200) << 9 | - (x & 0x400) << 10 | - (x & 0x800) << 11; - - unsigned int v = (y & 0x001) << 1 | - (y & 0x002) << 2 | - (y & 0x004) << 3 | - (y & 0x008) << 4 | - (y & 0x010) << 5 | - (y & 0x020) << 6 | - (y & 0x040) << 7 | - (y & 0x080) << 8 | - (y & 0x100) << 9 | - (y & 0x200) << 10 | - (y & 0x400) << 11 | - (y & 0x800) << 12; - - return bytes_per_pixel * (((u | v) & ~(~0 << 2*k)) | - (x & (~0 << k)) << k | - (y & (~0 << k)) << k); + return bytes_per_pixel * (fill_pattern(mask_x, x) + | fill_pattern(mask_y, y) + | fill_pattern(mask_z, z)); } -void swizzle_rect( +void swizzle_box( const uint8_t *src_buf, unsigned int width, unsigned int height, + unsigned int depth, uint8_t *dst_buf, - unsigned int pitch, + unsigned int row_pitch, + unsigned int slice_pitch, unsigned int bytes_per_pixel) { - int x, y; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - const uint8_t *src = src_buf+ (y * pitch + x * bytes_per_pixel); - uint8_t *dst = dst_buf + - get_swizzled_offset(x, y, width, height, bytes_per_pixel); - memcpy(dst, src, bytes_per_pixel); + uint32_t mask_x, mask_y, mask_z; + generate_swizzle_masks(width, height, depth, &mask_x, &mask_y, &mask_z); + + int x, y, z; + for (z = 0; z < depth; z++) { + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + const uint8_t *src = src_buf + + y * row_pitch + x * bytes_per_pixel; + uint8_t *dst = dst_buf + get_swizzled_offset(x, y, 0, + mask_x, mask_y, 0, + bytes_per_pixel); + memcpy(dst, src, bytes_per_pixel); + } } + src_buf += slice_pitch; + } +} + +void unswizzle_box( + const uint8_t *src_buf, + unsigned int width, + unsigned int height, + unsigned int depth, + uint8_t *dst_buf, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int bytes_per_pixel) +{ + uint32_t mask_x, mask_y, mask_z; + generate_swizzle_masks(width, height, depth, &mask_x, &mask_y, &mask_z); + + int x, y, z; + for (z = 0; z < depth; z++) { + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + const uint8_t *src = src_buf + + get_swizzled_offset(x, y, z, mask_x, mask_y, mask_z, + bytes_per_pixel); + uint8_t *dst = dst_buf + y * row_pitch + x * bytes_per_pixel; + memcpy(dst, src, bytes_per_pixel); + } + } + dst_buf += slice_pitch; } } @@ -98,13 +149,16 @@ void unswizzle_rect( unsigned int pitch, unsigned int bytes_per_pixel) { - int x, y; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - const uint8_t *src = src_buf - + get_swizzled_offset(x, y, width, height, bytes_per_pixel); - uint8_t *dst = dst_buf + (y * pitch + x * bytes_per_pixel); - memcpy(dst, src, bytes_per_pixel); - } - } -} \ No newline at end of file + unswizzle_box(src_buf, width, height, 1, dst_buf, pitch, 0, bytes_per_pixel); +} + +void swizzle_rect( + const uint8_t *src_buf, + unsigned int width, + unsigned int height, + uint8_t *dst_buf, + unsigned int pitch, + unsigned int bytes_per_pixel) +{ + swizzle_box(src_buf, width, height, 1, dst_buf, pitch, 0, bytes_per_pixel); +} diff --git a/hw/xbox/swizzle.h b/hw/xbox/swizzle.h index 2b9acd07d6..fa64b9a87d 100644 --- a/hw/xbox/swizzle.h +++ b/hw/xbox/swizzle.h @@ -22,6 +22,34 @@ #ifndef HW_XBOX_SWIZZLE_H #define HW_XBOX_SWIZZLE_H +void swizzle_box( + const uint8_t *src_buf, + unsigned int width, + unsigned int height, + unsigned int depth, + uint8_t *dst_buf, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int bytes_per_pixel); + +void unswizzle_box( + const uint8_t *src_buf, + unsigned int width, + unsigned int height, + unsigned int depth, + uint8_t *dst_buf, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int bytes_per_pixel); + +void unswizzle_rect( + const uint8_t *src_buf, + unsigned int width, + unsigned int height, + uint8_t *dst_buf, + unsigned int pitch, + unsigned int bytes_per_pixel); + void swizzle_rect( const uint8_t *src_buf, unsigned int width, @@ -30,12 +58,4 @@ void swizzle_rect( unsigned int pitch, unsigned int bytes_per_pixel); - void unswizzle_rect( - const uint8_t *src_buf, - unsigned int width, - unsigned int height, - uint8_t *dst_buf, - unsigned int pitch, - unsigned int bytes_per_pixel); - -#endif \ No newline at end of file +#endif From 0d4ee8ec2e0f8fcd5afc49c25d95dc420a2435f2 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Aug 2015 01:52:25 +0200 Subject: [PATCH 3/3] Volume texture support --- hw/xbox/nv2a.c | 71 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 1fab274d59..6072274d10 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -2104,15 +2104,19 @@ static void convert_yuy2_to_rgb(const uint8_t *line, unsigned int ix, static uint8_t* convert_texture_data(const TextureShape s, const uint8_t *data, const uint8_t *palette_data, - unsigned int width, unsigned int height, - unsigned int pitch) + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int row_pitch, + unsigned int slice_pitch) { if (s.color_format == NV097_SET_TEXTURE_FORMAT_COLOR_SZ_I8_A8R8G8B8) { + assert(depth == 1); /* FIXME */ uint8_t* converted_data = g_malloc(width * height * 4); int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - uint8_t index = data[y * pitch + x]; + uint8_t index = data[y * row_pitch + x]; uint32_t color = *(uint32_t*)(palette_data + index * 4); *(uint32_t*)(converted_data + y * width * 4 + x * 4) = color; } @@ -2120,6 +2124,7 @@ static uint8_t* convert_texture_data(const TextureShape s, return converted_data; } else if (s.color_format == NV097_SET_TEXTURE_FORMAT_COLOR_LC_IMAGE_CR8YB8CB8YA8) { + assert(depth == 1); /* FIXME */ uint8_t* converted_data = g_malloc(width * height * 4); int x, y; for (y = 0; y < height; y++) { @@ -2134,11 +2139,12 @@ static uint8_t* convert_texture_data(const TextureShape s, return converted_data; } else if (s.color_format == NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5) { + assert(depth == 1); /* FIXME */ uint8_t *converted_data = g_malloc(width * height * 3); int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - uint16_t rgb655 = *(uint16_t*)(data + y * pitch + x * 2); + uint16_t rgb655 = *(uint16_t*)(data + y * row_pitch + x * 2); int8_t *pixel = (int8_t*)&converted_data[(y * width + x) * 3]; /* Maps 5 bit G and B signed value range to 8 bit * signed values. R is probably unsigned. @@ -2155,10 +2161,10 @@ static uint8_t* convert_texture_data(const TextureShape s, } } -void pgraph_upload_gl_texture(GLenum gl_target, - const TextureShape s, - const uint8_t *texture_data, - const uint8_t *palette_data) +static void pgraph_upload_gl_texture(GLenum gl_target, + const TextureShape s, + const uint8_t *texture_data, + const uint8_t *palette_data) { ColorFormatInfo f = kelvin_color_format_map[s.color_format]; @@ -2166,9 +2172,6 @@ void pgraph_upload_gl_texture(GLenum gl_target, case GL_TEXTURE_1D: assert(false); break; - case GL_TEXTURE_3D: - assert(false); - break; case GL_TEXTURE_RECTANGLE: { /* Can't handle strides unaligned to pixels */ assert(s.pitch % f.bytes_per_pixel == 0); @@ -2177,7 +2180,8 @@ void pgraph_upload_gl_texture(GLenum gl_target, uint8_t *converted = convert_texture_data(s, texture_data, palette_data, - s.width, s.height, s.pitch); + s.width, s.height, 1, + s.pitch, 0); glTexImage2D(gl_target, 0, f.gl_internal_format, s.width, s.height, 0, @@ -2230,7 +2234,8 @@ void pgraph_upload_gl_texture(GLenum gl_target, uint8_t *converted = convert_texture_data(s, unswizzled, palette_data, - width, height, pitch); + width, height, 1, + pitch, 0); glTexImage2D(gl_target, level, f.gl_internal_format, width, height, 0, @@ -2251,6 +2256,45 @@ void pgraph_upload_gl_texture(GLenum gl_target, break; } + case GL_TEXTURE_3D: { + + unsigned int width = s.width, height = s.height, depth = s.depth; + + assert(f.gl_format != 0); /* FIXME: compressed not supported yet */ + assert(f.linear == false); + + int level; + for (level = 0; level < s.levels; level++) { + + unsigned int row_pitch = width * f.bytes_per_pixel; + unsigned int slice_pitch = row_pitch * height; + uint8_t *unswizzled = g_malloc(slice_pitch * depth); + unswizzle_box(texture_data, width, height, depth, unswizzled, + row_pitch, slice_pitch, f.bytes_per_pixel); + + uint8_t *converted = convert_texture_data(s, unswizzled, + palette_data, + width, height, depth, + row_pitch, slice_pitch); + + glTexImage3D(gl_target, level, f.gl_internal_format, + width, height, depth, 0, + f.gl_format, f.gl_type, + converted ? converted : unswizzled); + + if (converted) { + g_free(converted); + } + g_free(unswizzled); + + texture_data += width * height * depth * f.bytes_per_pixel; + + width /= 2; + height /= 2; + depth /= 2; + } + break; + } default: assert(false); break; @@ -2466,7 +2510,6 @@ static void pgraph_bind_textures(NV2AState *d) assert(!(filter & NV_PGRAPH_TEXFILTER0_RSIGNED)); assert(!(filter & NV_PGRAPH_TEXFILTER0_GSIGNED)); assert(!(filter & NV_PGRAPH_TEXFILTER0_BSIGNED)); - if (dimensionality != 2) continue; glActiveTexture(GL_TEXTURE0 + i); if (!enabled) {