mirror of https://github.com/xemu-project/xemu.git
Merge pull request #27 from JayFoxRox/cubemap-and-volume-textures
Cubemap and volume textures
This commit is contained in:
commit
87060feaac
256
hw/xbox/nv2a.c
256
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_TEXFILTER3 0x00001A00
|
||||||
#define NV_PGRAPH_TEXFMT0 0x00001A04
|
#define NV_PGRAPH_TEXFMT0 0x00001A04
|
||||||
# define NV_PGRAPH_TEXFMT0_CONTEXT_DMA (1 << 1)
|
# 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_DIMENSIONALITY 0x000000C0
|
||||||
# define NV_PGRAPH_TEXFMT0_COLOR 0x00007F00
|
# define NV_PGRAPH_TEXFMT0_COLOR 0x00007F00
|
||||||
# define NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS 0x000F0000
|
# define NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS 0x000F0000
|
||||||
|
@ -962,6 +963,7 @@ static void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...)
|
||||||
# define NV097_SET_TEXTURE_OFFSET 0x00971B00
|
# define NV097_SET_TEXTURE_OFFSET 0x00971B00
|
||||||
# define NV097_SET_TEXTURE_FORMAT 0x00971B04
|
# define NV097_SET_TEXTURE_FORMAT 0x00971B04
|
||||||
# define NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA 0x00000003
|
# 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_DIMENSIONALITY 0x000000F0
|
||||||
# define NV097_SET_TEXTURE_FORMAT_COLOR 0x0000FF00
|
# define NV097_SET_TEXTURE_FORMAT_COLOR 0x0000FF00
|
||||||
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_Y8 0x00
|
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_Y8 0x00
|
||||||
|
@ -1438,10 +1440,11 @@ typedef struct SurfaceShape {
|
||||||
} SurfaceShape;
|
} SurfaceShape;
|
||||||
|
|
||||||
typedef struct TextureShape {
|
typedef struct TextureShape {
|
||||||
|
bool cubemap;
|
||||||
unsigned int dimensionality;
|
unsigned int dimensionality;
|
||||||
unsigned int color_format;
|
unsigned int color_format;
|
||||||
unsigned int levels;
|
unsigned int levels;
|
||||||
unsigned int width, height;
|
unsigned int width, height, depth;
|
||||||
|
|
||||||
unsigned int min_mipmap_level, max_mipmap_level;
|
unsigned int min_mipmap_level, max_mipmap_level;
|
||||||
unsigned int pitch;
|
unsigned int pitch;
|
||||||
|
@ -2124,15 +2127,19 @@ static void convert_yuy2_to_rgb(const uint8_t *line, unsigned int ix,
|
||||||
static uint8_t* convert_texture_data(const TextureShape s,
|
static uint8_t* convert_texture_data(const TextureShape s,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
const uint8_t *palette_data,
|
const uint8_t *palette_data,
|
||||||
unsigned int width, unsigned int height,
|
unsigned int width,
|
||||||
unsigned int pitch)
|
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) {
|
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);
|
uint8_t* converted_data = g_malloc(width * height * 4);
|
||||||
int x, y;
|
int x, y;
|
||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
for (x = 0; x < width; x++) {
|
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 color = *(uint32_t*)(palette_data + index * 4);
|
||||||
*(uint32_t*)(converted_data + y * width * 4 + x * 4) = color;
|
*(uint32_t*)(converted_data + y * width * 4 + x * 4) = color;
|
||||||
}
|
}
|
||||||
|
@ -2140,6 +2147,7 @@ static uint8_t* convert_texture_data(const TextureShape s,
|
||||||
return converted_data;
|
return converted_data;
|
||||||
} else if (s.color_format
|
} else if (s.color_format
|
||||||
== NV097_SET_TEXTURE_FORMAT_COLOR_LC_IMAGE_CR8YB8CB8YA8) {
|
== NV097_SET_TEXTURE_FORMAT_COLOR_LC_IMAGE_CR8YB8CB8YA8) {
|
||||||
|
assert(depth == 1); /* FIXME */
|
||||||
uint8_t* converted_data = g_malloc(width * height * 4);
|
uint8_t* converted_data = g_malloc(width * height * 4);
|
||||||
int x, y;
|
int x, y;
|
||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
|
@ -2154,11 +2162,12 @@ static uint8_t* convert_texture_data(const TextureShape s,
|
||||||
return converted_data;
|
return converted_data;
|
||||||
} else if (s.color_format
|
} else if (s.color_format
|
||||||
== NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5) {
|
== NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5) {
|
||||||
|
assert(depth == 1); /* FIXME */
|
||||||
uint8_t *converted_data = g_malloc(width * height * 3);
|
uint8_t *converted_data = g_malloc(width * height * 3);
|
||||||
int x, y;
|
int x, y;
|
||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
for (x = 0; x < width; x++) {
|
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];
|
int8_t *pixel = (int8_t*)&converted_data[(y * width + x) * 3];
|
||||||
/* Maps 5 bit G and B signed value range to 8 bit
|
/* Maps 5 bit G and B signed value range to 8 bit
|
||||||
* signed values. R is probably unsigned.
|
* signed values. R is probably unsigned.
|
||||||
|
@ -2175,36 +2184,18 @@ static uint8_t* convert_texture_data(const TextureShape s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextureBinding* generate_texture(const TextureShape s,
|
static void pgraph_upload_gl_texture(GLenum gl_target,
|
||||||
const uint8_t *texture_data,
|
const TextureShape s,
|
||||||
const uint8_t *palette_data)
|
const uint8_t *texture_data,
|
||||||
|
const uint8_t *palette_data)
|
||||||
{
|
{
|
||||||
ColorFormatInfo f = kelvin_color_format_map[s.color_format];
|
ColorFormatInfo f = kelvin_color_format_map[s.color_format];
|
||||||
|
|
||||||
/* Create a new opengl texture */
|
switch(gl_target) {
|
||||||
GLuint gl_texture;
|
case GL_TEXTURE_1D:
|
||||||
glGenTextures(1, &gl_texture);
|
assert(false);
|
||||||
|
break;
|
||||||
GLenum gl_target;
|
case GL_TEXTURE_RECTANGLE: {
|
||||||
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) {
|
|
||||||
/* Can't handle strides unaligned to pixels */
|
/* Can't handle strides unaligned to pixels */
|
||||||
assert(s.pitch % f.bytes_per_pixel == 0);
|
assert(s.pitch % f.bytes_per_pixel == 0);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH,
|
glPixelStorei(GL_UNPACK_ROW_LENGTH,
|
||||||
|
@ -2212,7 +2203,8 @@ static TextureBinding* generate_texture(const TextureShape s,
|
||||||
|
|
||||||
uint8_t *converted = convert_texture_data(s, texture_data,
|
uint8_t *converted = convert_texture_data(s, texture_data,
|
||||||
palette_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,
|
glTexImage2D(gl_target, 0, f.gl_internal_format,
|
||||||
s.width, s.height, 0,
|
s.width, s.height, 0,
|
||||||
|
@ -2224,12 +2216,15 @@ static TextureBinding* generate_texture(const TextureShape s,
|
||||||
}
|
}
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
} else {
|
break;
|
||||||
|
}
|
||||||
glTexParameteri(gl_target, GL_TEXTURE_BASE_LEVEL,
|
case GL_TEXTURE_2D:
|
||||||
s.min_mipmap_level);
|
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||||
glTexParameteri(gl_target, GL_TEXTURE_MAX_LEVEL,
|
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||||
s.levels-1);
|
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;
|
unsigned int width = s.width, height = s.height;
|
||||||
|
|
||||||
|
@ -2262,7 +2257,8 @@ static TextureBinding* generate_texture(const TextureShape s,
|
||||||
|
|
||||||
uint8_t *converted = convert_texture_data(s, unswizzled,
|
uint8_t *converted = convert_texture_data(s, unswizzled,
|
||||||
palette_data,
|
palette_data,
|
||||||
width, height, pitch);
|
width, height, 1,
|
||||||
|
pitch, 0);
|
||||||
|
|
||||||
glTexImage2D(gl_target, level, f.gl_internal_format,
|
glTexImage2D(gl_target, level, f.gl_internal_format,
|
||||||
width, height, 0,
|
width, height, 0,
|
||||||
|
@ -2280,6 +2276,135 @@ static TextureBinding* generate_texture(const TextureShape s,
|
||||||
width /= 2;
|
width /= 2;
|
||||||
height /= 2;
|
height /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
if (f.gl_swizzle_mask[0] != 0 || f.gl_swizzle_mask[1] != 0
|
||||||
|
@ -2359,12 +2484,15 @@ static void pgraph_bind_textures(NV2AState *d)
|
||||||
|
|
||||||
unsigned int dma_select =
|
unsigned int dma_select =
|
||||||
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CONTEXT_DMA);
|
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CONTEXT_DMA);
|
||||||
|
bool cubemap =
|
||||||
|
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_CUBEMAPENABLE);
|
||||||
unsigned int dimensionality =
|
unsigned int dimensionality =
|
||||||
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_DIMENSIONALITY);
|
GET_MASK(fmt, NV_PGRAPH_TEXFMT0_DIMENSIONALITY);
|
||||||
unsigned int color_format = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_COLOR);
|
unsigned int color_format = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_COLOR);
|
||||||
unsigned int levels = GET_MASK(fmt, NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS);
|
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_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_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 =
|
unsigned int rect_width =
|
||||||
GET_MASK(pg->regs[NV_PGRAPH_TEXIMAGERECT0 + i*4],
|
GET_MASK(pg->regs[NV_PGRAPH_TEXIMAGERECT0 + i*4],
|
||||||
|
@ -2405,12 +2533,14 @@ static void pgraph_bind_textures(NV2AState *d)
|
||||||
assert(!(filter & NV_PGRAPH_TEXFILTER0_RSIGNED));
|
assert(!(filter & NV_PGRAPH_TEXFILTER0_RSIGNED));
|
||||||
assert(!(filter & NV_PGRAPH_TEXFILTER0_GSIGNED));
|
assert(!(filter & NV_PGRAPH_TEXFILTER0_GSIGNED));
|
||||||
assert(!(filter & NV_PGRAPH_TEXFILTER0_BSIGNED));
|
assert(!(filter & NV_PGRAPH_TEXFILTER0_BSIGNED));
|
||||||
if (dimensionality != 2) continue;
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
|
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_1D, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_3D, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2420,12 +2550,13 @@ static void pgraph_bind_textures(NV2AState *d)
|
||||||
continue;
|
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",
|
" filter %x %x, levels %d-%d %d bias %d\n",
|
||||||
i, color_format,
|
i, color_format,
|
||||||
rect_width, rect_height,
|
rect_width, rect_height,
|
||||||
1 << log_width, 1 << log_height,
|
1 << log_width, 1 << log_height, 1 << log_depth,
|
||||||
pitch,
|
pitch,
|
||||||
|
cubemap ? "; cubemap" : "",
|
||||||
min_filter, mag_filter,
|
min_filter, mag_filter,
|
||||||
min_mipmap_level, max_mipmap_level, levels,
|
min_mipmap_level, max_mipmap_level, levels,
|
||||||
lod_bias);
|
lod_bias);
|
||||||
|
@ -2434,13 +2565,16 @@ static void pgraph_bind_textures(NV2AState *d)
|
||||||
ColorFormatInfo f = kelvin_color_format_map[color_format];
|
ColorFormatInfo f = kelvin_color_format_map[color_format];
|
||||||
assert(f.bytes_per_pixel != 0);
|
assert(f.bytes_per_pixel != 0);
|
||||||
|
|
||||||
unsigned int width, height;
|
unsigned int width, height, depth;
|
||||||
if (f.linear) {
|
if (f.linear) {
|
||||||
|
assert(dimensionality == 2);
|
||||||
width = rect_width;
|
width = rect_width;
|
||||||
height = rect_height;
|
height = rect_height;
|
||||||
|
depth = 1;
|
||||||
} else {
|
} else {
|
||||||
width = 1 << log_width;
|
width = 1 << log_width;
|
||||||
height = 1 << log_height;
|
height = 1 << log_height;
|
||||||
|
depth = 1 << log_depth;
|
||||||
|
|
||||||
if (max_mipmap_level < levels) {
|
if (max_mipmap_level < levels) {
|
||||||
levels = max_mipmap_level;
|
levels = max_mipmap_level;
|
||||||
|
@ -2471,23 +2605,37 @@ static void pgraph_bind_textures(NV2AState *d)
|
||||||
|
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
if (f.linear) {
|
if (f.linear) {
|
||||||
|
assert(cubemap == false);
|
||||||
|
assert(dimensionality == 2);
|
||||||
length = height * pitch;
|
length = height * pitch;
|
||||||
} else {
|
} else {
|
||||||
unsigned int w = width, h = height;
|
if (dimensionality >= 2) {
|
||||||
int level;
|
unsigned int w = width, h = height;
|
||||||
for (level = 0; level < levels; level++) {
|
int level;
|
||||||
length += w * h * f.bytes_per_pixel;
|
for (level = 0; level < levels; level++) {
|
||||||
w /= 2;
|
/* FIXME: This is wrong for compressed textures and textures with 1x? non-square mipmaps */
|
||||||
h /= 2;
|
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 = {
|
TextureShape state = {
|
||||||
|
.cubemap = cubemap,
|
||||||
.dimensionality = dimensionality,
|
.dimensionality = dimensionality,
|
||||||
.color_format = color_format,
|
.color_format = color_format,
|
||||||
.levels = levels,
|
.levels = levels,
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
|
.depth = depth,
|
||||||
.min_mipmap_level = min_mipmap_level,
|
.min_mipmap_level = min_mipmap_level,
|
||||||
.max_mipmap_level = max_mipmap_level,
|
.max_mipmap_level = max_mipmap_level,
|
||||||
.pitch = pitch,
|
.pitch = pitch,
|
||||||
|
@ -5242,6 +5390,8 @@ static void pgraph_method(NV2AState *d,
|
||||||
|
|
||||||
bool dma_select =
|
bool dma_select =
|
||||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA) == 2;
|
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA) == 2;
|
||||||
|
bool cubemap =
|
||||||
|
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_CUBEMAP_ENABLE);
|
||||||
unsigned int dimensionality =
|
unsigned int dimensionality =
|
||||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_DIMENSIONALITY);
|
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_DIMENSIONALITY);
|
||||||
unsigned int color_format =
|
unsigned int color_format =
|
||||||
|
@ -5252,14 +5402,18 @@ static void pgraph_method(NV2AState *d,
|
||||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_U);
|
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_U);
|
||||||
unsigned int log_height =
|
unsigned int log_height =
|
||||||
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_V);
|
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];
|
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_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_DIMENSIONALITY, dimensionality);
|
||||||
SET_MASK(*reg, NV_PGRAPH_TEXFMT0_COLOR, color_format);
|
SET_MASK(*reg, NV_PGRAPH_TEXFMT0_COLOR, color_format);
|
||||||
SET_MASK(*reg, NV_PGRAPH_TEXFMT0_MIPMAP_LEVELS, levels);
|
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_U, log_width);
|
||||||
SET_MASK(*reg, NV_PGRAPH_TEXFMT0_BASE_SIZE_V, log_height);
|
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;
|
pg->texture_dirty[slot] = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -22,71 +22,122 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "hw/xbox/swizzle.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;
|
uint32_t x = 0, y = 0, z = 0;
|
||||||
while (i >>= 1) r++;
|
uint32_t bit = 1;
|
||||||
return r;
|
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(
|
static unsigned int get_swizzled_offset(
|
||||||
unsigned int x, unsigned int y,
|
unsigned int x, unsigned int y, unsigned int z,
|
||||||
unsigned int width, unsigned int height,
|
uint32_t mask_x, uint32_t mask_y, uint32_t mask_z,
|
||||||
unsigned int bytes_per_pixel)
|
unsigned int bytes_per_pixel)
|
||||||
{
|
{
|
||||||
unsigned int k = log2i(MIN(width, height));
|
return bytes_per_pixel * (fill_pattern(mask_x, x)
|
||||||
|
| fill_pattern(mask_y, y)
|
||||||
unsigned int u = (x & 0x001) << 0 |
|
| fill_pattern(mask_z, z));
|
||||||
(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void swizzle_rect(
|
void swizzle_box(
|
||||||
const uint8_t *src_buf,
|
const uint8_t *src_buf,
|
||||||
unsigned int width,
|
unsigned int width,
|
||||||
unsigned int height,
|
unsigned int height,
|
||||||
|
unsigned int depth,
|
||||||
uint8_t *dst_buf,
|
uint8_t *dst_buf,
|
||||||
unsigned int pitch,
|
unsigned int row_pitch,
|
||||||
|
unsigned int slice_pitch,
|
||||||
unsigned int bytes_per_pixel)
|
unsigned int bytes_per_pixel)
|
||||||
{
|
{
|
||||||
int x, y;
|
uint32_t mask_x, mask_y, mask_z;
|
||||||
for (y = 0; y < height; y++) {
|
generate_swizzle_masks(width, height, depth, &mask_x, &mask_y, &mask_z);
|
||||||
for (x = 0; x < width; x++) {
|
|
||||||
const uint8_t *src = src_buf+ (y * pitch + x * bytes_per_pixel);
|
int x, y, z;
|
||||||
uint8_t *dst = dst_buf +
|
for (z = 0; z < depth; z++) {
|
||||||
get_swizzled_offset(x, y, width, height, bytes_per_pixel);
|
for (y = 0; y < height; y++) {
|
||||||
memcpy(dst, src, bytes_per_pixel);
|
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 pitch,
|
||||||
unsigned int bytes_per_pixel)
|
unsigned int bytes_per_pixel)
|
||||||
{
|
{
|
||||||
int x, y;
|
unswizzle_box(src_buf, width, height, 1, dst_buf, pitch, 0, bytes_per_pixel);
|
||||||
for (y = 0; y < height; y++) {
|
}
|
||||||
for (x = 0; x < width; x++) {
|
|
||||||
const uint8_t *src = src_buf
|
void swizzle_rect(
|
||||||
+ get_swizzled_offset(x, y, width, height, bytes_per_pixel);
|
const uint8_t *src_buf,
|
||||||
uint8_t *dst = dst_buf + (y * pitch + x * bytes_per_pixel);
|
unsigned int width,
|
||||||
memcpy(dst, src, bytes_per_pixel);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,34 @@
|
||||||
#ifndef HW_XBOX_SWIZZLE_H
|
#ifndef HW_XBOX_SWIZZLE_H
|
||||||
#define 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(
|
void swizzle_rect(
|
||||||
const uint8_t *src_buf,
|
const uint8_t *src_buf,
|
||||||
unsigned int width,
|
unsigned int width,
|
||||||
|
@ -30,12 +58,4 @@ void swizzle_rect(
|
||||||
unsigned int pitch,
|
unsigned int pitch,
|
||||||
unsigned int bytes_per_pixel);
|
unsigned int bytes_per_pixel);
|
||||||
|
|
||||||
void unswizzle_rect(
|
#endif
|
||||||
const uint8_t *src_buf,
|
|
||||||
unsigned int width,
|
|
||||||
unsigned int height,
|
|
||||||
uint8_t *dst_buf,
|
|
||||||
unsigned int pitch,
|
|
||||||
unsigned int bytes_per_pixel);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in New Issue