From a86e44deb4a80302f1ae5820307157a143ae76eb Mon Sep 17 00:00:00 2001 From: raven02 Date: Mon, 8 Jun 2015 06:41:56 +0800 Subject: [PATCH] RSX: Fix NV3089 Make convert_swizzle.elf works --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 30 ---- rpcs3/Emu/RSX/RSXThread.cpp | 250 ++++++++++++++++++++++++++++---- rpcs3/Emu/RSX/RSXThread.h | 4 + 3 files changed, 222 insertions(+), 62 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 3b6f1f43e1..c19e47b5b6 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -2165,33 +2165,3 @@ void GLGSRender::semaphorePFIFOAcquire(u32 offset, u32 value) { } - -u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) -{ - u32 offset = 0; - u32 shift_count = 0; - while (log2_width | log2_height | log2_depth){ - if (log2_width) - { - offset |= (x & 0x01) << shift_count; - x >>= 1; - ++shift_count; - --log2_width; - } - if (log2_height) - { - offset |= (y & 0x01) << shift_count; - y >>= 1; - ++shift_count; - --log2_height; - } - if (log2_depth) - { - offset |= (z & 0x01) << shift_count; - z >>= 1; - ++shift_count; - --log2_depth; - } - } - return offset; -} diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index d3cd7129a4..e89762f72c 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -23,6 +23,39 @@ extern u64 get_system_time(); u32 methodRegisters[0xffff]; +u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) +{ + u32 offset = 0; + u32 shift_count = 0; + while (log2_width | log2_height | log2_depth) + { + if (log2_width) + { + offset |= (x & 0x01) << shift_count; + x >>= 1; + ++shift_count; + --log2_width; + } + + if (log2_height) + { + offset |= (y & 0x01) << shift_count; + y >>= 1; + ++shift_count; + --log2_height; + } + + if (log2_depth) + { + offset |= (z & 0x01) << shift_count; + z >>= 1; + ++shift_count; + --log2_depth; + } + } + return offset; +} + u32 GetAddress(u32 offset, u32 location) { u32 res = 0; @@ -2045,6 +2078,20 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV3062_SET_PITCH: + { + if (count == 1) + { + m_color_format_src_pitch = ARGS(0); + m_color_format_dst_pitch = ARGS(0) >> 16; + } + else + { + LOG_ERROR(RSX, "NV3062_SET_PITCH: unknown arg count (%d)", count); + } + break; + } + // NV309E case NV309E_SET_CONTEXT_DMA_IMAGE: { @@ -2075,6 +2122,19 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV309E_SET_OFFSET: + { + if (count == 1) + { + m_swizzle_offset = ARGS(0); + } + else + { + LOG_ERROR(RSX, "NV309E_SET_OFFSET: unknown arg count (%d)", count); + } + break; + } + // NV308A case NV308A_POINT: { @@ -2162,39 +2222,98 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3089_IMAGE_IN_SIZE: { - const u16 width = ARGS(0); - const u16 height = ARGS(0) >> 16; - const u16 pitch = ARGS(1); + if (count == 1) + { + m_img_in_size = ARGS(0); + + } + else + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown arg count (%d)", count); + } + break; + } + + case NV3089_IMAGE_IN_FORMAT: + { + if (count == 1) + { + m_img_in_format = ARGS(0); + + } + else + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown arg count (%d)", count); + } + break; + } + + case NV3089_IMAGE_IN_OFFSET: + { + if (count == 1) + { + m_src_offset = ARGS(0); + + } + else + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown arg count (%d)", count); + } + break; + } + + case NV3089_IMAGE_IN: + { + const u16 width = m_img_in_size; + const u16 height = m_img_in_size >> 16; + const u16 pitch = m_img_in_format; + const u8 origin = m_img_in_format >> 16; + const u8 inter = m_img_in_format >> 24; - const u8 origin = ARGS(1) >> 16; if (origin != 2 /* CELL_GCM_TRANSFER_ORIGIN_CORNER */) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", origin); } - const u8 inter = ARGS(1) >> 24; if (inter != 0 /* CELL_GCM_TRANSFER_INTERPOLATOR_ZOH */ && inter != 1 /* CELL_GCM_TRANSFER_INTERPOLATOR_FOH */) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown inter (%d)", inter); } - const u32 offset = ARGS(2); + const u32 src_offset = m_src_offset; + const u32 src_dma = m_context_dma_img_src; - const u16 u = ARGS(3); // inX (currently ignored) - const u16 v = ARGS(3) >> 16; // inY (currently ignored) + u32 dst_offset; + u32 dst_dma = 0; - u8* pixels_src = vm::get_ptr(GetAddress(offset, m_context_dma_img_src - 0xfeed0000)); - u8* pixels_dst = vm::get_ptr(GetAddress(m_dst_offset, m_context_dma_img_dst - 0xfeed0000)); - - if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D) - { - LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: Swizzle2D not implemented"); - } - else if (m_context_surface != CELL_GCM_CONTEXT_SURFACE2D) + switch (m_context_surface) { + case CELL_GCM_CONTEXT_SURFACE2D: + dst_dma = m_context_dma_img_dst; + dst_offset = m_dst_offset; + break; + + case CELL_GCM_CONTEXT_SWIZZLE2D: + dst_dma = m_context_dma_img_src; + dst_offset = m_swizzle_offset; + break; + + default: LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_context_surface (0x%x)", m_context_surface); + break; } + if (!dst_dma) + break; + + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: src = 0x%x, dst = 0x%x", src_offset, dst_offset); + + const u16 u = ARGS(0); // inX (currently ignored) + const u16 v = ARGS(0) >> 16; // inY (currently ignored) + + u8* pixels_src = vm::get_ptr(GetAddress(src_offset, src_dma)); + u8* pixels_dst = vm::get_ptr(GetAddress(dst_offset, dst_dma)); + if (m_color_format != 4 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 */ && m_color_format != 10 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 */) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_color_format (%d)", m_color_format); @@ -2206,11 +2325,42 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const s32 out_w = (s32)(u64(width) * (1 << 20) / m_color_conv_dsdx); const s32 out_h = (s32)(u64(height) * (1 << 20) / m_color_conv_dtdy); + if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D) + { + u8* linear_pixels = pixels_src; + u8* swizzled_pixels = new u8[in_bpp * width * height]; + + int sw_width = 1 << (int)log2(width); + int sw_height = 1 << (int)log2(height); + + for (int y = 0; y < sw_height; y++) + { + for (int x = 0; x < sw_width; x++) + { + switch (in_bpp) + { + case 1: + swizzled_pixels[LinearToSwizzleAddress(x, y, 0, sw_width, sw_height, 0)] = linear_pixels[y * sw_height + x]; + break; + case 2: + ((u16*)swizzled_pixels)[LinearToSwizzleAddress(x, y, 0, sw_width, sw_height, 0)] = ((u16*)linear_pixels)[y * sw_height + x]; + break; + case 4: + ((u32*)swizzled_pixels)[LinearToSwizzleAddress(x, y, 0, sw_width, sw_height, 0)] = ((u32*)linear_pixels)[y * sw_height + x]; + break; + } + + } + } + + pixels_src = swizzled_pixels; + } + LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: w=%d, h=%d, pitch=%d, offset=0x%x, inX=%f, inY=%f, scaleX=%f, scaleY=%f", - width, height, pitch, offset, double(u) / 16, double(v) / 16, double(1 << 20) / (m_color_conv_dsdx), double(1 << 20) / (m_color_conv_dtdy)); + width, height, pitch, src_offset, double(u) / 16, double(v) / 16, double(1 << 20) / (m_color_conv_dsdx), double(1 << 20) / (m_color_conv_dtdy)); std::unique_ptr temp; - + if (in_bpp != out_bpp && width != out_w && height != out_h) { // resize/convert if necessary @@ -2220,7 +2370,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const AVPixelFormat in_format = m_color_format == 4 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB; // ??? AVPixelFormat out_format = m_color_conv_fmt == 7 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB; // ??? - std::unique_ptr sws(sws_getContext(width, height, in_format, out_w, out_h, out_format, inter ? SWS_FAST_BILINEAR : SWS_POINT, NULL, NULL, NULL), sws_freeContext); + std::unique_ptr sws(sws_getContext(width, height, in_format, out_w, out_h, out_format, + inter ? SWS_FAST_BILINEAR : SWS_POINT, NULL, NULL, NULL), sws_freeContext); int in_line = in_bpp * width; u8* out_ptr = temp.get(); @@ -2272,6 +2423,11 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const memcpy(pixels_dst, pixels_src, out_w * out_h * out_bpp); } + if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D) + { + delete[] pixels_src; + } + break; } @@ -2308,6 +2464,49 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV3089_SET_COLOR_FORMAT: + m_color_conv_fmt = ARGS(0); + if (m_color_conv_fmt != 3 /* CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 */ && m_color_conv_fmt != 7 /* CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 */) + { + LOG_ERROR(RSX, "NV3089_SET_COLOR_FORMAT: unknown format (%d)", m_color_conv_fmt); + } + break; + + case NV3089_SET_OPERATION: + m_color_conv_op = ARGS(0); + if (m_color_conv_op != 3 /* CELL_GCM_TRANSFER_OPERATION_SRCCOPY */) + { + LOG_ERROR(RSX, "NV3089_SET_OPERATION: unknown color conv op (%d)", m_color_conv_op); + } + break; + case NV3089_CLIP_POINT: + m_color_conv_clip_x = ARGS(0); + m_color_conv_clip_y = ARGS(0) >> 16; + break; + + case NV3089_CLIP_SIZE: + m_color_conv_clip_w = ARGS(0); + m_color_conv_clip_h = ARGS(0) >> 16; + break; + + case NV3089_IMAGE_OUT_POINT: + m_color_conv_out_x = ARGS(0); + m_color_conv_out_y = ARGS(0) >> 16; + break; + + case NV3089_IMAGE_OUT_SIZE: + m_color_conv_out_w = ARGS(0); + m_color_conv_out_h = ARGS(0) >> 16; + break; + + case NV3089_DS_DX: + m_color_conv_dsdx = ARGS(0); + break; + + case NV3089_DT_DY: + m_color_conv_dtdy = ARGS(0); + break; + case GCM_SET_USER_COMMAND: { const u32 cause = ARGS(0); @@ -2353,7 +2552,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3062_SET_OBJECT: case NV3062_SET_CONTEXT_DMA_NOTIFIES: case NV3062_SET_CONTEXT_DMA_IMAGE_SOURCE: - case NV3062_SET_PITCH: case NV3062_SET_OFFSET_SOURCE: { LOG_WARNING(RSX, "Unused NV3062 method 0x%x detected!", cmd); @@ -2381,7 +2579,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV309E_SET_OBJECT: case NV309E_SET_CONTEXT_DMA_NOTIFIES: - case NV309E_SET_OFFSET: { LOG_WARNING(RSX, "Unused NV309E method 0x%x detected!", cmd); break; @@ -2393,17 +2590,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3089_SET_CONTEXT_ROP: case NV3089_SET_CONTEXT_BETA1: case NV3089_SET_CONTEXT_BETA4: - case NV3089_SET_COLOR_FORMAT: - case NV3089_SET_OPERATION: - case NV3089_CLIP_POINT: - case NV3089_CLIP_SIZE: - case NV3089_IMAGE_OUT_POINT: - case NV3089_IMAGE_OUT_SIZE: - case NV3089_DS_DX: - case NV3089_DT_DY: - case NV3089_IMAGE_IN_FORMAT: - case NV3089_IMAGE_IN_OFFSET: - case NV3089_IMAGE_IN: { LOG_WARNING(RSX, "Unused NV3089 methods 0x%x detected!", cmd); break; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index ded727a469..6dcf387b38 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -19,6 +19,7 @@ enum Method extern u32 methodRegisters[0xffff]; u32 GetAddress(u32 offset, u32 location); +u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth); struct RSXVertexData { @@ -407,6 +408,9 @@ public: u32 m_context_dma_buffer_in_src; u32 m_context_dma_buffer_in_dst; u32 m_dst_offset; + u32 m_src_offset; + u32 m_img_in_size; + u32 m_img_in_format; // Swizzle2D? u16 m_swizzle_format;