diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 46edb5f7e5..7fb1ed6811 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -948,6 +948,14 @@ static const u32 mr_color_dma[rsx::limits::color_buffers_count] = NV4097_SET_CONTEXT_DMA_COLOR_D }; +static const u32 mr_color_pitch[rsx::limits::color_buffers_count] = +{ + NV4097_SET_SURFACE_PITCH_A, + NV4097_SET_SURFACE_PITCH_B, + NV4097_SET_SURFACE_PITCH_C, + NV4097_SET_SURFACE_PITCH_D +}; + void GLGSRender::read_buffers() { if (!draw_fbo) @@ -963,7 +971,16 @@ void GLGSRender::read_buffers() { for (int i = index; i < index + count; ++i) { - u32 color_address = rsx::get_address(rsx::method_registers[mr_color_offset[i]], rsx::method_registers[mr_color_dma[i]]); + u32 offset = rsx::method_registers[mr_color_offset[i]]; + u32 location = rsx::method_registers[mr_color_dma[i]]; + u32 pitch = rsx::method_registers[mr_color_pitch[i]]; + + if (pitch <= 64) + continue; + + m_draw_tex_color[i].pixel_unpack_settings().row_length(pitch / (color_format.channel_size * color_format.channel_count)); + + u32 color_address = rsx::get_address(offset, location); __glcheck m_draw_tex_color[i].copy_from(vm::base(color_address), color_format.format, color_format.type); } }; @@ -1065,7 +1082,16 @@ void GLGSRender::write_buffers() //}, gl::buffer::access::read); - u32 color_address = rsx::get_address(rsx::method_registers[mr_color_offset[i]], rsx::method_registers[mr_color_dma[i]]); + u32 offset = rsx::method_registers[mr_color_offset[i]]; + u32 location = rsx::method_registers[mr_color_dma[i]]; + u32 pitch = rsx::method_registers[mr_color_pitch[i]]; + + if (pitch <= 64) + continue; + + m_draw_tex_color[i].pixel_pack_settings().row_length(pitch / (color_format.channel_size * color_format.channel_count)); + + u32 color_address = rsx::get_address(offset, location); __glcheck m_draw_tex_color[i].copy_to(vm::base(color_address), color_format.format, color_format.type); } }; @@ -1173,8 +1199,7 @@ void GLGSRender::flip(int buffer) .type(gl::texture::type::uint_8_8_8_8) .format(gl::texture::format::bgra); - m_flip_tex_color.pixel_unpack_settings().aligment(1); - m_flip_tex_color.pixel_pack_settings().aligment(1); + m_flip_tex_color.pixel_unpack_settings().aligment(1).row_length(buffer_pitch); __glcheck m_flip_fbo.recreate(); __glcheck m_flip_fbo.color = m_flip_tex_color; diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp index 6653eace01..baad5818f7 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -4,11 +4,45 @@ #include "../GCM.h" #include "../RSXThread.h" #include "../RSXTexture.h" +#include "../rsx_utils.h" namespace rsx { namespace gl { + static const int gl_tex_min_filter[] = + { + GL_NEAREST, // unused + GL_NEAREST, + GL_LINEAR, + GL_NEAREST_MIPMAP_NEAREST, + GL_LINEAR_MIPMAP_NEAREST, + GL_NEAREST_MIPMAP_LINEAR, + GL_LINEAR_MIPMAP_LINEAR, + GL_NEAREST, // CELL_GCM_TEXTURE_CONVOLUTION_MIN + }; + + static const int gl_tex_mag_filter[] = + { + GL_NEAREST, // unused + GL_NEAREST, + GL_LINEAR, + GL_NEAREST, // unused + GL_LINEAR // CELL_GCM_TEXTURE_CONVOLUTION_MAG + }; + + static const int gl_tex_zfunc[] = + { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS, + }; + void texture::create() { if (m_id) @@ -59,7 +93,9 @@ namespace rsx void texture::init(rsx::texture& tex) { if (!m_id) + { create(); + } bind(); @@ -69,8 +105,10 @@ namespace rsx //TODO: safe init - int format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - bool is_swizzled = !(tex.format() & CELL_GCM_TEXTURE_LN); + u32 full_format = tex.format(); + + u32 format = full_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + bool is_swizzled = ~full_format & CELL_GCM_TEXTURE_LN; const u8* pixels = vm::ps3::_ptr(texaddr); u8 *unswizzledPixels; @@ -78,10 +116,16 @@ namespace rsx // NOTE: This must be in ARGB order in all forms below. const GLint *glRemap = glRemapStandard; + ::gl::pixel_pack_settings().apply(); + ::gl::pixel_unpack_settings().apply(); + + u32 pitch = tex.pitch(); + switch (format) { case CELL_GCM_TEXTURE_B8: // One 8-bit fixed-point number { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BLUE, GL_UNSIGNED_BYTE, pixels); static const GLint swizzleMaskB8[] = { GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE }; @@ -92,6 +136,7 @@ namespace rsx case CELL_GCM_TEXTURE_A1R5G5B5: { glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); // TODO: texture swizzling glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels); @@ -101,6 +146,7 @@ namespace rsx case CELL_GCM_TEXTURE_A4R4G4B4: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels); // We read it in as R4G4B4A4, so we need to remap each component. @@ -111,6 +157,7 @@ namespace rsx case CELL_GCM_TEXTURE_R5G6B5: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.width(), tex.height(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -119,6 +166,8 @@ namespace rsx case CELL_GCM_TEXTURE_A8R8G8B8: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); + if (is_swizzled) { u32 *src, *dst; @@ -167,6 +216,7 @@ namespace rsx case CELL_GCM_TEXTURE_G8B8: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_UNSIGNED_BYTE, pixels); static const GLint swizzleMaskG8B8[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN }; @@ -176,6 +226,8 @@ namespace rsx case CELL_GCM_TEXTURE_R6G5B5: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); + // TODO: Probably need to actually unswizzle if is_swizzled. const u32 numPixels = tex.width() * tex.height(); unswizzledPixels = (u8 *)malloc(numPixels * 4); @@ -196,30 +248,36 @@ namespace rsx case CELL_GCM_TEXTURE_DEPTH24_D8: // 24-bit unsigned fixed-point number and 8 bits of garbage { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pixels); break; } case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // 24-bit unsigned float and 8 bits of garbage { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels); break; } case CELL_GCM_TEXTURE_DEPTH16: // 16-bit unsigned fixed-point number { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_SHORT, pixels); break; } case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // 16-bit unsigned float { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.width(), tex.height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels); break; } case CELL_GCM_TEXTURE_X16: // A 16-bit fixed-point number { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RED, GL_UNSIGNED_SHORT, pixels); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -231,6 +289,7 @@ namespace rsx case CELL_GCM_TEXTURE_Y16_X16: // Two 16-bit fixed-point numbers { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_UNSIGNED_SHORT, pixels); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -241,6 +300,7 @@ namespace rsx case CELL_GCM_TEXTURE_R5G5B5A1: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -249,6 +309,7 @@ namespace rsx case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: // Four fp16 values { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 8); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_HALF_FLOAT, pixels); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -257,12 +318,16 @@ namespace rsx case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: // Four fp32 values { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_FLOAT, pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 16); + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_FLOAT, pixels); + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); break; } case CELL_GCM_TEXTURE_X32_FLOAT: // One 32-bit floating-point number { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RED, GL_FLOAT, pixels); static const GLint swizzleMaskX32_FLOAT[] = { GL_RED, GL_ONE, GL_ONE, GL_ONE }; @@ -272,9 +337,9 @@ namespace rsx case CELL_GCM_TEXTURE_D1R5G5B5: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 2); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); - // TODO: Texture swizzling glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels); @@ -287,6 +352,7 @@ namespace rsx case CELL_GCM_TEXTURE_D8R8G8B8: // 8 bits of garbage and three unsigned 8-bit fixed-point numbers { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels); static const GLint swizzleMaskX32_D8R8G8B8[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE }; @@ -297,6 +363,7 @@ namespace rsx case CELL_GCM_TEXTURE_Y16_X16_FLOAT: // Two fp16 values { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RG, GL_HALF_FLOAT, pixels); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -308,6 +375,8 @@ namespace rsx case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); + const u32 numPixels = tex.width() * tex.height(); unswizzledPixels = (u8 *)malloc(numPixels * 4); // TODO: Speed. @@ -332,6 +401,8 @@ namespace rsx case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: { + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / 4); + const u32 numPixels = tex.width() * tex.height(); unswizzledPixels = (u8 *)malloc(numPixels * 4); // TODO: Speed. @@ -385,18 +456,6 @@ namespace rsx glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[3]); } - static const int gl_tex_zfunc[] = - { - GL_NEVER, - GL_LESS, - GL_EQUAL, - GL_LEQUAL, - GL_GREATER, - GL_NOTEQUAL, - GL_GEQUAL, - GL_ALWAYS, - }; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s())); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t())); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r())); @@ -407,34 +466,10 @@ namespace rsx glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8)); - - - static const int gl_tex_min_filter[] = - { - GL_NEAREST, // unused - GL_NEAREST, - GL_LINEAR, - GL_NEAREST_MIPMAP_NEAREST, - GL_LINEAR_MIPMAP_NEAREST, - GL_NEAREST_MIPMAP_LINEAR, - GL_LINEAR_MIPMAP_LINEAR, - GL_NEAREST, // CELL_GCM_TEXTURE_CONVOLUTION_MIN - }; - - static const int gl_tex_mag_filter[] = { - GL_NEAREST, // unused - GL_NEAREST, - GL_LINEAR, - GL_NEAREST, // unused - GL_LINEAR // CELL_GCM_TEXTURE_CONVOLUTION_MAG - }; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_min_filter[tex.min_filter()]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter[tex.mag_filter()]); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso())); - //Unbind(); - if (is_swizzled && format == CELL_GCM_TEXTURE_A8R8G8B8) { free(unswizzledPixels); diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 33ad93be5f..7fdff4d2dd 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -8,17 +8,16 @@ extern "C" namespace rsx { template - void pad_texture(void* inputPixels, void* outputPixels, u16 inputWidth, u16 inputHeight, u16 outputWidth, u16 outputHeight) + void pad_texture(void* input_pixels, void* output_pixels, u16 input_width, u16 input_height, u16 output_width, u16 output_height) { - T *src, *dst; - src = static_cast(inputPixels); - dst = static_cast(outputPixels); + T *src = static_cast(input_pixels); + T *dst = static_cast(output_pixels); for (u16 h = 0; h < inputHeight; ++h) { - const u32 padded_pos = h * outputWidth; - const u32 pos = h * inputWidth; - for (u16 w = 0; w < inputWidth; ++w) + const u32 padded_pos = h * output_width; + const u32 pos = h * input_width; + for (u16 w = 0; w < input_width; ++w) { dst[padded_pos + w] = src[pos + w]; } @@ -31,12 +30,10 @@ namespace rsx * Restriction: It has mixed results if the height or width is not a power of 2 */ template - void convert_linear_swizzle(void* inputPixels, void* outputPixels, u16 width, u16 height, bool inputIsSwizzled) + void convert_linear_swizzle(void* input_pixels, void* output_pixels, u16 width, u16 height, bool input_is_swizzled) { - u32 log2width, log2height; - - log2width = log2(width); - log2height = log2(height); + u32 log2width = log2(width); + u32 log2height = log2(height); // Max mask possible for square texture u32 x_mask = 0x55555555; @@ -57,38 +54,48 @@ namespace rsx u32 offs_x0 = 0; //total y-carry offset for x u32 y_incr = limit_mask; - T *src, *dst; - - if (!inputIsSwizzled) + if (!input_is_swizzled) { for (int y = 0; y < height; ++y) { - src = static_cast(inputPixels) + y*width; - dst = static_cast(outputPixels) + offs_y; + T *src = static_cast(input_pixels) + y * width; + T *dst = static_cast(output_pixels) + offs_y; offs_x = offs_x0; + for (int x = 0; x < width; ++x) { dst[offs_x] = src[x]; offs_x = (offs_x - x_mask) & x_mask; } + offs_y = (offs_y - y_mask) & y_mask; - if (offs_y == 0) offs_x0 += y_incr; + + if (offs_y == 0) + { + offs_x0 += y_incr; + } } } else { for (int y = 0; y < height; ++y) { - src = static_cast(inputPixels) + offs_y; - dst = static_cast(outputPixels) + y*width; + T *src = static_cast(input_pixels) + offs_y; + T *dst = static_cast(output_pixels) + y * width; offs_x = offs_x0; + for (int x = 0; x < width; ++x) { dst[x] = src[offs_x]; offs_x = (offs_x - x_mask) & x_mask; } + offs_y = (offs_y - y_mask) & y_mask; - if (offs_y == 0) offs_x0 += y_incr; + + if (offs_y == 0) + { + offs_x0 += y_incr; + } } } }