mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
Added missed files
This commit is contained in:
parent
48919330d7
commit
c1be0cf3bf
839
rpcs3/Emu/RSX/rsx_methods.cpp
Normal file
839
rpcs3/Emu/RSX/rsx_methods.cpp
Normal file
@ -0,0 +1,839 @@
|
||||
#include "stdafx.h"
|
||||
#include "rsx_methods.h"
|
||||
#include "RSXThread.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/state.h"
|
||||
#include "rsx_utils.h"
|
||||
#include "Emu/SysCalls/Callback.h"
|
||||
#include "Emu/SysCalls/CB_FUNC.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
u32 method_registers[0x10000 >> 2];
|
||||
rsx_method_t methods[0x10000 >> 2]{};
|
||||
|
||||
template<typename Type> struct vertex_data_type_from_element_type;
|
||||
template<> struct vertex_data_type_from_element_type<float> { enum { type = CELL_GCM_VERTEX_F }; };
|
||||
template<> struct vertex_data_type_from_element_type<f16> { enum { type = CELL_GCM_VERTEX_SF }; };
|
||||
template<> struct vertex_data_type_from_element_type<u8> { enum { type = CELL_GCM_VERTEX_UB }; };
|
||||
template<> struct vertex_data_type_from_element_type<u16> { enum { type = CELL_GCM_VERTEX_S1 }; };
|
||||
|
||||
namespace nv406e
|
||||
{
|
||||
force_inline void set_reference(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->ctrl->ref.exchange(arg);
|
||||
}
|
||||
|
||||
force_inline void semaphore_acquire(thread* rsx, u32 arg)
|
||||
{
|
||||
//TODO: dma
|
||||
while (vm::ps3::read32(rsx->label_addr + method_registers[NV406E_SEMAPHORE_OFFSET]) != arg)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
force_inline void semaphore_release(thread* rsx, u32 arg)
|
||||
{
|
||||
//TODO: dma
|
||||
vm::ps3::write32(rsx->label_addr + method_registers[NV406E_SEMAPHORE_OFFSET], arg);
|
||||
}
|
||||
}
|
||||
|
||||
namespace nv4097
|
||||
{
|
||||
force_inline void texture_read_semaphore_release(thread* rsx, u32 arg)
|
||||
{
|
||||
//TODO: dma
|
||||
vm::ps3::write32(rsx->label_addr + method_registers[NV4097_SET_SEMAPHORE_OFFSET], arg);
|
||||
}
|
||||
|
||||
force_inline void back_end_write_semaphore_release(thread* rsx, u32 arg)
|
||||
{
|
||||
//TODO: dma
|
||||
vm::ps3::write32(rsx->label_addr + method_registers[NV4097_SET_SEMAPHORE_OFFSET],
|
||||
(arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
|
||||
}
|
||||
|
||||
//fire only when all data passed to rsx cmd buffer
|
||||
template<u32 id, u32 index, int count, typename type>
|
||||
force_inline void set_vertex_data_impl(thread* rsx, u32 arg)
|
||||
{
|
||||
static const size_t element_size = (count * sizeof(type));
|
||||
static const size_t element_size_in_words = element_size / sizeof(u32);
|
||||
|
||||
auto& info = rsx->register_vertex_info[index];
|
||||
|
||||
info.type = vertex_data_type_from_element_type<type>::type;
|
||||
info.size = count;
|
||||
info.frequency = 0;
|
||||
info.stride = 0;
|
||||
|
||||
auto& entry = rsx->register_vertex_data[index];
|
||||
|
||||
//find begin of data
|
||||
size_t begin = id + index * element_size_in_words;
|
||||
|
||||
size_t position = 0;//entry.size();
|
||||
entry.resize(position + element_size);
|
||||
|
||||
memcpy(entry.data() + position, method_registers + begin, element_size);
|
||||
}
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data4ub_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA4UB_M, index, 4, u8>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data1f_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA1F_M, index, 1, f32>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data2f_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA2F_M, index, 2, f32>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data3f_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA3F_M, index, 3, f32>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data4f_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA4F_M, index, 4, f32>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data2s_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA2S_M, index, 2, u16>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data4s_m
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
set_vertex_data_impl<NV4097_SET_VERTEX_DATA4S_M, index, 4, u16>(rsx, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_vertex_data_array_format
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
auto& info = rsx->vertex_arrays_info[index];
|
||||
info.unpack_array(arg);
|
||||
}
|
||||
};
|
||||
|
||||
force_inline void draw_arrays(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->draw_command = thread::Draw_command::draw_command_array;
|
||||
u32 first = arg & 0xffffff;
|
||||
u32 count = (arg >> 24) + 1;
|
||||
|
||||
rsx->load_vertex_data(first, count);
|
||||
}
|
||||
|
||||
force_inline void draw_index_array(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->draw_command = thread::Draw_command::draw_command_indexed;
|
||||
u32 first = arg & 0xffffff;
|
||||
u32 count = (arg >> 24) + 1;
|
||||
|
||||
rsx->load_vertex_data(first, count);
|
||||
rsx->load_vertex_index_data(first, count);
|
||||
}
|
||||
|
||||
force_inline void draw_inline_array(thread* rsx, u32 arg)
|
||||
{
|
||||
rsx->draw_command = thread::Draw_command::draw_command_inlined_array;
|
||||
rsx->draw_inline_vertex_array = true;
|
||||
rsx->inline_vertex_array.push_back(arg);
|
||||
}
|
||||
|
||||
template<u32 index>
|
||||
struct set_transform_constant
|
||||
{
|
||||
force_inline static void impl(thread* rsxthr, u32 arg)
|
||||
{
|
||||
u32 load = method_registers[NV4097_SET_TRANSFORM_CONSTANT_LOAD];
|
||||
|
||||
static const size_t count = 4;
|
||||
static const size_t size = count * sizeof(f32);
|
||||
|
||||
size_t reg = index / 4;
|
||||
size_t subreg = index % 4;
|
||||
|
||||
memcpy(rsxthr->transform_constants[load + reg].rgba + subreg, method_registers + NV4097_SET_TRANSFORM_CONSTANT + reg * count + subreg, sizeof(f32));
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 index>
|
||||
struct set_transform_program
|
||||
{
|
||||
force_inline static void impl(thread* rsx, u32 arg)
|
||||
{
|
||||
u32& load = method_registers[NV4097_SET_TRANSFORM_PROGRAM_LOAD];
|
||||
|
||||
static const size_t count = 4;
|
||||
static const size_t size = count * sizeof(u32);
|
||||
|
||||
memcpy(rsx->transform_program + load++ * count, method_registers + NV4097_SET_TRANSFORM_PROGRAM + index * count, size);
|
||||
}
|
||||
};
|
||||
|
||||
force_inline void set_begin_end(thread* rsx, u32 arg)
|
||||
{
|
||||
if (arg)
|
||||
{
|
||||
rsx->draw_inline_vertex_array = false;
|
||||
rsx->inline_vertex_array.clear();
|
||||
rsx->begin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rsx->vertex_draw_count)
|
||||
{
|
||||
bool has_array = false;
|
||||
|
||||
for (int i = 0; i < rsx::limits::vertex_count; ++i)
|
||||
{
|
||||
if (rsx->vertex_arrays_info[i].size > 0)
|
||||
{
|
||||
has_array = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_array)
|
||||
{
|
||||
u32 min_count = ~0;
|
||||
|
||||
for (int i = 0; i < rsx::limits::vertex_count; ++i)
|
||||
{
|
||||
if (!rsx->register_vertex_info[i].size)
|
||||
continue;
|
||||
|
||||
u32 count = u32(rsx->register_vertex_data[i].size()) /
|
||||
rsx::get_vertex_type_size(rsx->register_vertex_info[i].type) * rsx->register_vertex_info[i].size;
|
||||
|
||||
if (count < min_count)
|
||||
min_count = count;
|
||||
}
|
||||
|
||||
if (min_count && min_count < ~0)
|
||||
{
|
||||
rsx->vertex_draw_count = min_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rsx->end();
|
||||
rsx->vertex_draw_count = 0;
|
||||
}
|
||||
|
||||
force_inline void get_report(thread* rsx, u32 arg)
|
||||
{
|
||||
u8 type = arg >> 24;
|
||||
u32 offset = arg & 0xffffff;
|
||||
|
||||
//TODO: use DMA
|
||||
vm::ps3::ptr<CellGcmReportData> result = { rsx->local_mem_addr + offset, vm::addr };
|
||||
|
||||
result->timer = rsx->timestamp();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_ZPASS_PIXEL_CNT:
|
||||
case CELL_GCM_ZCULL_STATS:
|
||||
case CELL_GCM_ZCULL_STATS1:
|
||||
case CELL_GCM_ZCULL_STATS2:
|
||||
case CELL_GCM_ZCULL_STATS3:
|
||||
result->value = 0;
|
||||
LOG_WARNING(RSX, "NV4097_GET_REPORT: Unimplemented type %d", type);
|
||||
break;
|
||||
|
||||
default:
|
||||
result->value = 0;
|
||||
LOG_ERROR(RSX, "NV4097_GET_REPORT: Bad type %d", type);
|
||||
break;
|
||||
}
|
||||
|
||||
//result->padding = 0;
|
||||
}
|
||||
|
||||
force_inline void clear_report_value(thread* rsx, u32 arg)
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
case CELL_GCM_ZPASS_PIXEL_CNT:
|
||||
LOG_WARNING(RSX, "TODO: NV4097_CLEAR_REPORT_VALUE: ZPASS_PIXEL_CNT");
|
||||
break;
|
||||
case CELL_GCM_ZCULL_STATS:
|
||||
LOG_WARNING(RSX, "TODO: NV4097_CLEAR_REPORT_VALUE: ZCULL_STATS");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(RSX, "NV4097_CLEAR_REPORT_VALUE: Bad type: %d", arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace nv308a
|
||||
{
|
||||
template<u32 index>
|
||||
struct color
|
||||
{
|
||||
force_inline static void impl(u32 arg)
|
||||
{
|
||||
u32 point = method_registers[NV308A_POINT];
|
||||
u16 x = point;
|
||||
u16 y = point >> 16;
|
||||
|
||||
if (y)
|
||||
{
|
||||
LOG_ERROR(RSX, "%s: y is not null (0x%x)", __FUNCTION__, y);
|
||||
}
|
||||
|
||||
u32 address = get_address(method_registers[NV3062_SET_OFFSET_DESTIN] + (x << 2) + index * 4, method_registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN]);
|
||||
vm::ps3::write32(address, arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace nv3089
|
||||
{
|
||||
never_inline void image_in(u32 arg)
|
||||
{
|
||||
u32 operation = method_registers[NV3089_SET_OPERATION];
|
||||
|
||||
u32 clip_x = method_registers[NV3089_CLIP_POINT] & 0xffff;
|
||||
u32 clip_y = method_registers[NV3089_CLIP_POINT] >> 16;
|
||||
u32 clip_w = method_registers[NV3089_CLIP_SIZE] & 0xffff;
|
||||
u32 clip_h = method_registers[NV3089_CLIP_SIZE] >> 16;
|
||||
|
||||
u32 out_x = method_registers[NV3089_IMAGE_OUT_POINT] & 0xffff;
|
||||
u32 out_y = method_registers[NV3089_IMAGE_OUT_POINT] >> 16;
|
||||
u32 out_w = method_registers[NV3089_IMAGE_OUT_SIZE] & 0xffff;
|
||||
u32 out_h = method_registers[NV3089_IMAGE_OUT_SIZE] >> 16;
|
||||
|
||||
u16 in_w = method_registers[NV3089_IMAGE_IN_SIZE];
|
||||
u16 in_h = method_registers[NV3089_IMAGE_IN_SIZE] >> 16;
|
||||
u16 in_pitch = method_registers[NV3089_IMAGE_IN_FORMAT];
|
||||
u8 in_origin = method_registers[NV3089_IMAGE_IN_FORMAT] >> 16;
|
||||
u8 in_inter = method_registers[NV3089_IMAGE_IN_FORMAT] >> 24;
|
||||
u32 src_color_format = method_registers[NV3089_SET_COLOR_FORMAT];
|
||||
|
||||
f32 in_x = (method_registers[NV3089_IMAGE_IN] & 0xffff) / 16.f;
|
||||
f32 in_y = (method_registers[NV3089_IMAGE_IN] >> 16) / 16.f;
|
||||
|
||||
if (in_origin != CELL_GCM_TRANSFER_ORIGIN_CORNER)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", in_origin);
|
||||
}
|
||||
|
||||
if (in_inter != CELL_GCM_TRANSFER_INTERPOLATOR_ZOH && in_inter != CELL_GCM_TRANSFER_INTERPOLATOR_FOH)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown inter (%d)", in_inter);
|
||||
}
|
||||
|
||||
if (operation != CELL_GCM_TRANSFER_OPERATION_SRCCOPY)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown operation (%d)", operation);
|
||||
}
|
||||
|
||||
const u32 src_offset = method_registers[NV3089_IMAGE_IN_OFFSET];
|
||||
const u32 src_dma = method_registers[NV3089_SET_CONTEXT_DMA_IMAGE];
|
||||
|
||||
u32 dst_offset;
|
||||
u32 dst_dma = 0;
|
||||
u16 dst_color_format;
|
||||
u32 out_pitch = 0;
|
||||
u32 out_aligment = 64;
|
||||
|
||||
switch (method_registers[NV3089_SET_CONTEXT_SURFACE])
|
||||
{
|
||||
case CELL_GCM_CONTEXT_SURFACE2D:
|
||||
dst_dma = method_registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN];
|
||||
dst_offset = method_registers[NV3062_SET_OFFSET_DESTIN];
|
||||
dst_color_format = method_registers[NV3062_SET_COLOR_FORMAT];
|
||||
out_pitch = method_registers[NV3062_SET_PITCH] >> 16;
|
||||
out_aligment = method_registers[NV3062_SET_PITCH] & 0xffff;
|
||||
break;
|
||||
|
||||
case CELL_GCM_CONTEXT_SWIZZLE2D:
|
||||
dst_dma = method_registers[NV309E_SET_CONTEXT_DMA_IMAGE];
|
||||
dst_offset = method_registers[NV309E_SET_OFFSET];
|
||||
dst_color_format = method_registers[NV309E_SET_FORMAT];
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_context_surface (0x%x)", method_registers[NV3089_SET_CONTEXT_SURFACE]);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 src_address = get_address(src_offset, src_dma);
|
||||
u32 dst_address = get_address(dst_offset, dst_dma);
|
||||
|
||||
u32 in_bpp = src_color_format == CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 ? 2 : 4; // bytes per pixel
|
||||
u32 out_bpp = dst_color_format == CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 ? 2 : 4;
|
||||
|
||||
if (out_pitch == 0)
|
||||
{
|
||||
out_pitch = out_bpp * out_w;
|
||||
}
|
||||
|
||||
if (in_pitch == 0)
|
||||
{
|
||||
in_pitch = in_bpp * in_w;
|
||||
}
|
||||
|
||||
if (clip_w > out_w)
|
||||
{
|
||||
clip_w = out_w;
|
||||
}
|
||||
|
||||
if (clip_h > out_h)
|
||||
{
|
||||
clip_h = out_h;
|
||||
}
|
||||
|
||||
//LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: src = 0x%x, dst = 0x%x", src_address, dst_address);
|
||||
|
||||
u8* pixels_src = vm::ps3::_ptr<u8>(src_address);
|
||||
u8* pixels_dst = vm::ps3::_ptr<u8>(dst_address);
|
||||
|
||||
if (dst_color_format != CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 &&
|
||||
dst_color_format != CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown dst_color_format (%d)", dst_color_format);
|
||||
}
|
||||
|
||||
if (src_color_format != CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 &&
|
||||
src_color_format != CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown src_color_format (%d)", src_color_format);
|
||||
}
|
||||
|
||||
//LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: SIZE=0x%08x, pitch=0x%x, offset=0x%x, scaleX=%f, scaleY=%f, CLIP_SIZE=0x%08x, OUT_SIZE=0x%08x",
|
||||
// method_registers[NV3089_IMAGE_IN_SIZE], in_pitch, src_offset, double(1 << 20) / (method_registers[NV3089_DS_DX]), double(1 << 20) / (method_registers[NV3089_DT_DY]),
|
||||
// method_registers[NV3089_CLIP_SIZE], method_registers[NV3089_IMAGE_OUT_SIZE]);
|
||||
|
||||
std::unique_ptr<u8[]> temp1, temp2;
|
||||
|
||||
AVPixelFormat in_format = src_color_format == CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB;
|
||||
AVPixelFormat out_format = dst_color_format == CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB;
|
||||
|
||||
u32 out_offset = out_x * out_bpp + out_pitch * out_y;
|
||||
|
||||
bool need_clip = method_registers[NV3089_CLIP_SIZE] != method_registers[NV3089_IMAGE_IN_SIZE] || method_registers[NV3089_CLIP_POINT];
|
||||
bool need_convert = out_format != in_format || out_w != in_w || out_h != in_h;
|
||||
|
||||
u32 slice_h = (u32)(clip_h * (method_registers[NV3089_DS_DX] / 1048576.f));
|
||||
|
||||
if (slice_h)
|
||||
{
|
||||
if (clip_h < out_h)
|
||||
{
|
||||
--slice_h;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
slice_h = clip_h;
|
||||
}
|
||||
|
||||
if (method_registers[NV3089_SET_CONTEXT_SURFACE] != CELL_GCM_CONTEXT_SWIZZLE2D)
|
||||
{
|
||||
if (need_convert || need_clip)
|
||||
{
|
||||
if (need_clip)
|
||||
{
|
||||
if (need_convert)
|
||||
{
|
||||
convert_scale_image(temp1, out_format, out_w, out_h, out_pitch,
|
||||
pixels_src, in_format, in_w, in_h, in_pitch, slice_h, in_inter ? true : false);
|
||||
|
||||
clip_image(pixels_dst + out_offset, temp1.get(), clip_x, clip_y, clip_w, clip_h, out_bpp, out_pitch, out_pitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
clip_image(pixels_dst + out_offset, pixels_src, clip_x, clip_y, clip_w, clip_h, out_bpp, in_pitch, out_pitch);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
convert_scale_image(pixels_dst + out_offset, out_format, out_w, out_h, out_pitch,
|
||||
pixels_src, in_format, in_w, in_h, in_pitch, slice_h, in_inter ? true : false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (out_pitch != in_pitch || out_pitch != out_bpp * out_w)
|
||||
{
|
||||
for (u32 y = 0; y < out_h; ++y)
|
||||
{
|
||||
u8 *dst = pixels_dst + out_x * out_bpp + out_pitch * (y + out_y);
|
||||
u8 *src = pixels_src + in_pitch * y;
|
||||
|
||||
std::memmove(dst, src, out_w * out_bpp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memmove(pixels_dst + out_offset, pixels_src, out_pitch * out_h);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_convert || need_clip)
|
||||
{
|
||||
if (need_clip)
|
||||
{
|
||||
if (need_convert)
|
||||
{
|
||||
convert_scale_image(temp1, out_format, out_w, out_h, out_pitch,
|
||||
pixels_src, in_format, in_w, in_h, in_pitch, slice_h, in_inter ? true : false);
|
||||
|
||||
clip_image(temp2, temp1.get(), clip_x, clip_y, clip_w, clip_h, out_bpp, out_pitch, out_pitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
clip_image(temp2, pixels_src, clip_x, clip_y, clip_w, clip_h, out_bpp, in_pitch, out_pitch);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
convert_scale_image(temp2, out_format, out_w, out_h, out_pitch,
|
||||
pixels_src, in_format, in_w, in_h, in_pitch, clip_h, in_inter ? true : false);
|
||||
}
|
||||
|
||||
pixels_src = temp2.get();
|
||||
}
|
||||
|
||||
u8 sw_width_log2 = method_registers[NV309E_SET_FORMAT] >> 16;
|
||||
u8 sw_height_log2 = method_registers[NV309E_SET_FORMAT] >> 24;
|
||||
|
||||
// 0 indicates height of 1 pixel
|
||||
sw_height_log2 = sw_height_log2 == 0 ? 1 : sw_height_log2;
|
||||
|
||||
// swizzle based on destination size
|
||||
u16 sw_width = 1 << sw_width_log2;
|
||||
u16 sw_height = 1 << sw_height_log2;
|
||||
|
||||
temp2.reset(new u8[out_bpp * sw_width * sw_height]);
|
||||
|
||||
u8* linear_pixels = pixels_src;
|
||||
u8* swizzled_pixels = temp2.get();
|
||||
|
||||
// Check and pad texture out if we are given non square texture for swizzle to be correct
|
||||
if (sw_width != out_w || sw_height != out_h)
|
||||
{
|
||||
std::unique_ptr<u8[]> sw_temp(new u8[out_bpp * sw_width * sw_height]);
|
||||
|
||||
switch (out_bpp)
|
||||
{
|
||||
case 1:
|
||||
pad_texture<u8>(linear_pixels, sw_temp.get(), out_w, out_h, sw_width, sw_height);
|
||||
break;
|
||||
case 2:
|
||||
pad_texture<u16>(linear_pixels, sw_temp.get(), out_w, out_h, sw_width, sw_height);
|
||||
break;
|
||||
case 4:
|
||||
pad_texture<u32>(linear_pixels, sw_temp.get(), out_w, out_h, sw_width, sw_height);
|
||||
break;
|
||||
}
|
||||
|
||||
linear_pixels = sw_temp.get();
|
||||
}
|
||||
|
||||
switch (out_bpp)
|
||||
{
|
||||
case 1:
|
||||
convert_linear_swizzle<u8>(linear_pixels, swizzled_pixels, sw_width, sw_height, false);
|
||||
break;
|
||||
case 2:
|
||||
convert_linear_swizzle<u16>(linear_pixels, swizzled_pixels, sw_width, sw_height, false);
|
||||
break;
|
||||
case 4:
|
||||
convert_linear_swizzle<u32>(linear_pixels, swizzled_pixels, sw_width, sw_height, false);
|
||||
break;
|
||||
}
|
||||
|
||||
std::memcpy(pixels_dst, swizzled_pixels, out_bpp * sw_width * sw_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace nv0039
|
||||
{
|
||||
force_inline void buffer_notify(u32 arg)
|
||||
{
|
||||
const u32 inPitch = method_registers[NV0039_PITCH_IN];
|
||||
const u32 outPitch = method_registers[NV0039_PITCH_OUT];
|
||||
const u32 lineLength = method_registers[NV0039_LINE_LENGTH_IN];
|
||||
const u32 lineCount = method_registers[NV0039_LINE_COUNT];
|
||||
const u8 outFormat = method_registers[NV0039_FORMAT] >> 8;
|
||||
const u8 inFormat = method_registers[NV0039_FORMAT];
|
||||
const u32 notify = arg;
|
||||
|
||||
// The existing GCM commands use only the value 0x1 for inFormat and outFormat
|
||||
if (inFormat != 0x01 || outFormat != 0x01)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", inFormat, outFormat);
|
||||
}
|
||||
|
||||
if (lineCount == 1 && !inPitch && !outPitch && !notify)
|
||||
{
|
||||
std::memcpy(
|
||||
vm::base(get_address(method_registers[NV0039_OFFSET_OUT], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT])),
|
||||
vm::base(get_address(method_registers[NV0039_OFFSET_IN], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN])),
|
||||
lineLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(RSX, "NV0039_OFFSET_IN: bad offset(in=0x%x, out=0x%x), pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
method_registers[NV0039_OFFSET_IN], method_registers[NV0039_OFFSET_OUT], inPitch, outPitch, lineLength, lineCount, inFormat, outFormat, notify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flip_command(thread* rsx, u32 arg)
|
||||
{
|
||||
if (user_asked_for_frame_capture)
|
||||
{
|
||||
rsx->capture_current_frame = true;
|
||||
user_asked_for_frame_capture = false;
|
||||
frame_debug.reset();
|
||||
}
|
||||
else if (rsx->capture_current_frame)
|
||||
{
|
||||
rsx->capture_current_frame = false;
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
rsx->gcm_current_buffer = arg;
|
||||
rsx->flip(arg);
|
||||
// After each flip PS3 system is executing a routine that changes registers value to some default.
|
||||
// Some game use this default state (SH3).
|
||||
rsx->reset();
|
||||
|
||||
rsx->last_flip_time = get_system_time() - 1000000;
|
||||
rsx->gcm_current_buffer = arg;
|
||||
rsx->flip_status = 0;
|
||||
|
||||
if (rsx->flip_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([func = rsx->flip_handler](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, 1);
|
||||
});
|
||||
}
|
||||
|
||||
rsx->sem_flip.post_and_wait();
|
||||
|
||||
//sync
|
||||
double limit;
|
||||
switch (rpcs3::state.config.rsx.frame_limit.value())
|
||||
{
|
||||
case rsx_frame_limit::_50: limit = 50.; break;
|
||||
case rsx_frame_limit::_59_94: limit = 59.94; break;
|
||||
case rsx_frame_limit::_30: limit = 30.; break;
|
||||
case rsx_frame_limit::_60: limit = 60.; break;
|
||||
case rsx_frame_limit::Auto: limit = rsx->fps_limit; break; //TODO
|
||||
|
||||
case rsx_frame_limit::Off:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec())));
|
||||
rsx->timer_sync.Start();
|
||||
rsx->local_transform_constants.clear();
|
||||
}
|
||||
|
||||
void user_command(thread* rsx, u32 arg)
|
||||
{
|
||||
if (rsx->user_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([func = rsx->user_handler, arg](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, arg);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("User handler not set");
|
||||
}
|
||||
}
|
||||
|
||||
struct __rsx_methods_t
|
||||
{
|
||||
using rsx_impl_method_t = void(*)(u32);
|
||||
|
||||
template<rsx_method_t impl_func>
|
||||
force_inline static void call_impl_func(thread *rsx, u32 arg)
|
||||
{
|
||||
impl_func(rsx, arg);
|
||||
}
|
||||
|
||||
template<rsx_impl_method_t impl_func>
|
||||
force_inline static void call_impl_func(thread *rsx, u32 arg)
|
||||
{
|
||||
impl_func(arg);
|
||||
}
|
||||
|
||||
template<int id, typename T, T impl_func>
|
||||
static void wrapper(thread *rsx, u32 arg)
|
||||
{
|
||||
// try process using gpu
|
||||
if (rsx->do_method(id, arg))
|
||||
{
|
||||
if (rsx->capture_current_frame && id == NV4097_CLEAR_SURFACE)
|
||||
rsx->capture_frame("clear");
|
||||
return;
|
||||
}
|
||||
|
||||
// not handled by renderer
|
||||
// try process using cpu
|
||||
if (impl_func != nullptr)
|
||||
call_impl_func<impl_func>(rsx, arg);
|
||||
}
|
||||
|
||||
template<int id, int step, int count, template<u32> class T, int index = 0>
|
||||
struct bind_range_impl_t
|
||||
{
|
||||
force_inline static void impl()
|
||||
{
|
||||
bind_range_impl_t<id + step, step, count, T, index + 1>::impl();
|
||||
bind<id, T<index>::impl>();
|
||||
}
|
||||
};
|
||||
|
||||
template<int id, int step, int count, template<u32> class T>
|
||||
struct bind_range_impl_t<id, step, count, T, count>
|
||||
{
|
||||
force_inline static void impl()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<int id, int step, int count, template<u32> class T, int index = 0>
|
||||
force_inline static void bind_range()
|
||||
{
|
||||
bind_range_impl_t<id, step, count, T, index>::impl();
|
||||
}
|
||||
|
||||
[[noreturn]] never_inline static void bind_redefinition_error(int id)
|
||||
{
|
||||
throw EXCEPTION("RSX method implementation redefinition (0x%04x)", id);
|
||||
}
|
||||
|
||||
template<int id, typename T, T impl_func>
|
||||
static void bind_impl()
|
||||
{
|
||||
if (methods[id])
|
||||
{
|
||||
bind_redefinition_error(id);
|
||||
}
|
||||
|
||||
methods[id] = wrapper<id, T, impl_func>;
|
||||
}
|
||||
|
||||
template<int id, typename T, T impl_func>
|
||||
static void bind_cpu_only_impl()
|
||||
{
|
||||
if (methods[id])
|
||||
{
|
||||
bind_redefinition_error(id);
|
||||
}
|
||||
|
||||
methods[id] = call_impl_func<impl_func>;
|
||||
}
|
||||
|
||||
template<int id, rsx_impl_method_t impl_func> static void bind() { bind_impl<id, rsx_impl_method_t, impl_func>(); }
|
||||
template<int id, rsx_method_t impl_func = nullptr> static void bind() { bind_impl<id, rsx_method_t, impl_func>(); }
|
||||
|
||||
//do not try process on gpu
|
||||
template<int id, rsx_impl_method_t impl_func> static void bind_cpu_only() { bind_cpu_only_impl<id, rsx_impl_method_t, impl_func>(); }
|
||||
//do not try process on gpu
|
||||
template<int id, rsx_method_t impl_func = nullptr> static void bind_cpu_only() { bind_cpu_only_impl<id, rsx_method_t, impl_func>(); }
|
||||
|
||||
__rsx_methods_t()
|
||||
{
|
||||
// NV406E
|
||||
bind_cpu_only<NV406E_SET_REFERENCE, nv406e::set_reference>();
|
||||
bind<NV406E_SEMAPHORE_ACQUIRE, nv406e::semaphore_acquire>();
|
||||
bind<NV406E_SEMAPHORE_RELEASE, nv406e::semaphore_release>();
|
||||
|
||||
// NV4097
|
||||
bind<NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, nv4097::texture_read_semaphore_release>();
|
||||
bind<NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE, nv4097::back_end_write_semaphore_release>();
|
||||
bind<NV4097_SET_BEGIN_END, nv4097::set_begin_end>();
|
||||
bind<NV4097_CLEAR_SURFACE>();
|
||||
bind<NV4097_DRAW_ARRAYS, nv4097::draw_arrays>();
|
||||
bind<NV4097_DRAW_INDEX_ARRAY, nv4097::draw_index_array>();
|
||||
bind<NV4097_INLINE_ARRAY, nv4097::draw_inline_array>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 1, 16, nv4097::set_vertex_data_array_format>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA4UB_M, 1, 16, nv4097::set_vertex_data4ub_m>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA1F_M, 1, 16, nv4097::set_vertex_data1f_m>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA2F_M + 1, 2, 16, nv4097::set_vertex_data2f_m>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA3F_M + 2, 3, 16, nv4097::set_vertex_data3f_m>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA4F_M + 3, 4, 16, nv4097::set_vertex_data4f_m>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA2S_M, 1, 16, nv4097::set_vertex_data2s_m>();
|
||||
bind_range<NV4097_SET_VERTEX_DATA4S_M + 1, 2, 16, nv4097::set_vertex_data4s_m>();
|
||||
bind_range<NV4097_SET_TRANSFORM_CONSTANT, 1, 32, nv4097::set_transform_constant>();
|
||||
bind_range<NV4097_SET_TRANSFORM_PROGRAM + 3, 4, 128, nv4097::set_transform_program>();
|
||||
bind_cpu_only<NV4097_GET_REPORT, nv4097::get_report>();
|
||||
bind_cpu_only<NV4097_CLEAR_REPORT_VALUE, nv4097::clear_report_value>();
|
||||
|
||||
//NV308A
|
||||
bind_range<NV308A_COLOR, 1, 256, nv308a::color>();
|
||||
bind_range<NV308A_COLOR + 256, 1, 512, nv308a::color, 256>();
|
||||
|
||||
//NV3089
|
||||
bind<NV3089_IMAGE_IN, nv3089::image_in>();
|
||||
|
||||
//NV0039
|
||||
bind<NV0039_BUFFER_NOTIFY, nv0039::buffer_notify>();
|
||||
|
||||
// custom methods
|
||||
bind_cpu_only<GCM_FLIP_COMMAND, flip_command>();
|
||||
bind_cpu_only<GCM_SET_USER_COMMAND, user_command>();
|
||||
}
|
||||
} __rsx_methods;
|
||||
}
|
69
rpcs3/Emu/RSX/rsx_methods.h
Normal file
69
rpcs3/Emu/RSX/rsx_methods.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
//TODO
|
||||
union alignas(4) method_registers_t
|
||||
{
|
||||
u8 _u8[0x10000];
|
||||
u32 _u32[0x10000 >> 2];
|
||||
/*
|
||||
struct alignas(4)
|
||||
{
|
||||
u8 pad[NV4097_SET_TEXTURE_OFFSET - 4];
|
||||
|
||||
struct alignas(4) texture_t
|
||||
{
|
||||
u32 offset;
|
||||
|
||||
union format_t
|
||||
{
|
||||
u32 _u32;
|
||||
|
||||
struct
|
||||
{
|
||||
u32: 1;
|
||||
u32 location : 1;
|
||||
u32 cubemap : 1;
|
||||
u32 border_type : 1;
|
||||
u32 dimension : 4;
|
||||
u32 format : 8;
|
||||
u32 mipmap : 16;
|
||||
};
|
||||
} format;
|
||||
|
||||
union address_t
|
||||
{
|
||||
u32 _u32;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 wrap_s : 4;
|
||||
u32 aniso_bias : 4;
|
||||
u32 wrap_t : 4;
|
||||
u32 unsigned_remap : 4;
|
||||
u32 wrap_r : 4;
|
||||
u32 gamma : 4;
|
||||
u32 signed_remap : 4;
|
||||
u32 zfunc : 4;
|
||||
};
|
||||
} address;
|
||||
|
||||
u32 control0;
|
||||
u32 control1;
|
||||
u32 filter;
|
||||
u32 image_rect;
|
||||
u32 border_color;
|
||||
} textures[limits::textures_count];
|
||||
};
|
||||
*/
|
||||
u32& operator[](int index)
|
||||
{
|
||||
return _u32[index >> 2];
|
||||
}
|
||||
};
|
||||
|
||||
using rsx_method_t = void(*)(class thread*, u32);
|
||||
extern u32 method_registers[0x10000 >> 2];
|
||||
extern rsx_method_t methods[0x10000 >> 2];
|
||||
}
|
Loading…
Reference in New Issue
Block a user