2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2015-10-26 22:09:31 +01:00
|
|
|
#include "Emu/state.h"
|
2014-10-09 23:26:04 +02:00
|
|
|
#include "Emu/RSX/GSManager.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "RSXThread.h"
|
2014-09-11 21:18:19 +02:00
|
|
|
|
|
|
|
|
#include "Emu/SysCalls/Callback.h"
|
2014-11-10 01:21:50 +01:00
|
|
|
#include "Emu/SysCalls/CB_FUNC.h"
|
2015-10-11 22:00:51 +02:00
|
|
|
#include "Emu/SysCalls/lv2/sys_time.h"
|
|
|
|
|
|
2015-10-14 19:47:09 +02:00
|
|
|
#include "Common/BufferUtils.h"
|
2016-01-05 17:42:54 +01:00
|
|
|
#include "rsx_utils.h"
|
2015-10-14 19:47:09 +02:00
|
|
|
|
2015-10-09 20:04:20 +02:00
|
|
|
#define CMD_DEBUG 0
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-11-06 00:56:27 +01:00
|
|
|
bool user_asked_for_frame_capture = false;
|
|
|
|
|
frame_capture_data frame_debug;
|
2015-10-08 15:53:21 +02:00
|
|
|
|
|
|
|
|
namespace rsx
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
using rsx_method_t = void(*)(thread*, u32);
|
|
|
|
|
|
2015-10-08 15:53:21 +02:00
|
|
|
u32 method_registers[0x10000 >> 2];
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx_method_t methods[0x10000 >> 2]{};
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 01:07:47 +02:00
|
|
|
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 }; };
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
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::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::write32(rsx->label_addr + method_registers[NV406E_SEMAPHORE_OFFSET], arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 01:07:47 +02:00
|
|
|
namespace nv4097
|
|
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
force_inline void texture_read_semaphore_release(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
//TODO: dma
|
2015-10-13 19:39:36 +02:00
|
|
|
vm::write32(rsx->label_addr + method_registers[NV4097_SET_SEMAPHORE_OFFSET], arg);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
force_inline void back_end_write_semaphore_release(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
//TODO: dma
|
2015-10-13 19:39:36 +02:00
|
|
|
vm::write32(rsx->label_addr + method_registers[NV4097_SET_SEMAPHORE_OFFSET],
|
|
|
|
|
(arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-11 01:07:47 +02:00
|
|
|
//fire only when all data passed to rsx cmd buffer
|
|
|
|
|
template<u32 id, u32 index, int count, typename type>
|
2015-10-11 20:59:46 +02:00
|
|
|
force_inline void set_vertex_data_impl(thread* rsx, u32 arg)
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
|
|
|
|
static const size_t element_size = (count * sizeof(type));
|
|
|
|
|
static const size_t element_size_in_words = element_size / sizeof(u32);
|
|
|
|
|
|
2015-12-23 22:25:02 +01:00
|
|
|
auto& info = rsx->register_vertex_info[index];
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
info.type = vertex_data_type_from_element_type<type>::type;
|
|
|
|
|
info.size = count;
|
|
|
|
|
info.frequency = 0;
|
|
|
|
|
info.stride = 0;
|
|
|
|
|
|
2015-12-23 22:25:02 +01:00
|
|
|
auto& entry = rsx->register_vertex_data[index];
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
//find begin of data
|
|
|
|
|
size_t begin = id + index * element_size_in_words;
|
|
|
|
|
|
2015-12-23 22:25:02 +01:00
|
|
|
size_t position = 0;//entry.size();
|
2015-10-11 01:07:47 +02:00
|
|
|
entry.resize(position + element_size);
|
|
|
|
|
|
|
|
|
|
memcpy(entry.data() + position, method_registers + begin, element_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data4ub_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA4UB_M, index, 4, u8>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data1f_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA1F_M, index, 1, f32>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data2f_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA2F_M, index, 2, f32>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data3f_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA3F_M, index, 3, f32>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data4f_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA4F_M, index, 4, f32>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data2s_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA2S_M, index, 2, u16>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data4s_m
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
set_vertex_data_impl<NV4097_SET_VERTEX_DATA4S_M, index, 4, u16>(rsx, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_vertex_data_array_format
|
2015-10-11 01:07:47 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
auto& info = rsx->vertex_arrays_info[index];
|
2015-12-23 22:25:02 +01:00
|
|
|
info.unpack_array(arg);
|
2015-10-13 19:44:58 +02:00
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 01:07:47 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
force_inline void draw_arrays(thread* rsx, u32 arg)
|
2015-10-08 17:07:23 +02:00
|
|
|
{
|
2015-12-31 19:15:44 +01:00
|
|
|
rsx->draw_command = thread::Draw_command::draw_command_array;
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 first = arg & 0xffffff;
|
|
|
|
|
u32 count = (arg >> 24) + 1;
|
2015-10-08 17:07:23 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx->load_vertex_data(first, count);
|
2015-10-08 17:07:23 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
force_inline void draw_index_array(thread* rsx, u32 arg)
|
|
|
|
|
{
|
2015-12-31 19:15:44 +01:00
|
|
|
rsx->draw_command = thread::Draw_command::draw_command_indexed;
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 first = arg & 0xffffff;
|
|
|
|
|
u32 count = (arg >> 24) + 1;
|
2015-10-08 15:53:21 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx->load_vertex_data(first, count);
|
|
|
|
|
rsx->load_vertex_index_data(first, count);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-31 19:15:44 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_transform_constant
|
2013-11-09 22:29:49 +01:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsxthr, u32 arg)
|
|
|
|
|
{
|
2015-11-12 18:13:28 +01:00
|
|
|
u32 load = method_registers[NV4097_SET_TRANSFORM_CONSTANT_LOAD];
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
static const size_t count = 4;
|
|
|
|
|
static const size_t size = count * sizeof(f32);
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-11-12 18:13:28 +01:00
|
|
|
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));
|
2015-10-13 19:44:58 +02:00
|
|
|
}
|
|
|
|
|
};
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct set_transform_program
|
2015-10-08 15:53:21 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(thread* rsx, u32 arg)
|
|
|
|
|
{
|
|
|
|
|
u32& load = method_registers[NV4097_SET_TRANSFORM_PROGRAM_LOAD];
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
static const size_t count = 4;
|
|
|
|
|
static const size_t size = count * sizeof(u32);
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
memcpy(rsx->transform_program + load++ * count, method_registers + NV4097_SET_TRANSFORM_PROGRAM + index * count, size);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-08 17:07:23 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
force_inline void set_begin_end(thread* rsx, u32 arg)
|
2015-10-08 15:53:21 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
if (arg)
|
2015-10-08 15:53:21 +02:00
|
|
|
{
|
2015-12-31 19:15:44 +01:00
|
|
|
rsx->draw_inline_vertex_array = false;
|
|
|
|
|
rsx->inline_vertex_array.clear();
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx->begin();
|
|
|
|
|
return;
|
2015-10-08 15:53:21 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
if (!rsx->vertex_draw_count)
|
|
|
|
|
{
|
|
|
|
|
bool has_array = false;
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
for (int i = 0; i < rsx::limits::vertex_count; ++i)
|
|
|
|
|
{
|
2015-12-23 22:25:02 +01:00
|
|
|
if (rsx->vertex_arrays_info[i].size > 0)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
|
|
|
|
has_array = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!has_array)
|
|
|
|
|
{
|
|
|
|
|
u32 min_count = ~0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < rsx::limits::vertex_count; ++i)
|
|
|
|
|
{
|
2015-12-23 22:25:02 +01:00
|
|
|
if (!rsx->register_vertex_info[i].size)
|
2015-10-11 22:00:51 +02:00
|
|
|
continue;
|
|
|
|
|
|
2015-12-23 22:25:02 +01:00
|
|
|
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;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
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;
|
2015-10-08 15:53:21 +02:00
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
force_inline void get_report(thread* rsx, u32 arg)
|
2015-10-04 00:45:26 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
u8 type = arg >> 24;
|
|
|
|
|
u32 offset = arg & 0xffffff;
|
|
|
|
|
|
|
|
|
|
//TODO: use DMA
|
2015-09-26 22:46:04 +02:00
|
|
|
vm::ptr<CellGcmReportData> result = { rsx->local_mem_addr + offset, vm::addr };
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
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;
|
2013-11-09 22:29:49 +01:00
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2015-10-08 17:07:23 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
namespace nv308a
|
2015-10-08 17:07:23 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
template<u32 index>
|
2015-10-13 19:44:58 +02:00
|
|
|
struct color
|
2015-10-08 17:07:23 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl(u32 arg)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
u32 point = method_registers[NV308A_POINT];
|
|
|
|
|
u16 x = point;
|
|
|
|
|
u16 y = point >> 16;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
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::write32(address, arg);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-08 17:07:23 +02:00
|
|
|
}
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
namespace nv3089
|
|
|
|
|
{
|
2015-10-14 21:34:26 +02:00
|
|
|
never_inline void image_in(u32 arg)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2016-01-05 17:46:28 +01:00
|
|
|
u32 operation = method_registers[NV3089_SET_OPERATION];
|
2015-10-11 20:59:46 +02:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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;
|
2015-12-01 14:55:15 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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];
|
2015-12-01 14:55:15 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
f32 in_x = (method_registers[NV3089_IMAGE_IN] & 0xffff) / 16.f;
|
|
|
|
|
f32 in_y = (method_registers[NV3089_IMAGE_IN] >> 16) / 16.f;
|
2015-12-01 14:55:15 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
if (in_origin != CELL_GCM_TRANSFER_ORIGIN_CORNER)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2016-01-05 17:46:28 +01:00
|
|
|
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", in_origin);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
if (in_inter != CELL_GCM_TRANSFER_INTERPOLATOR_ZOH && in_inter != CELL_GCM_TRANSFER_INTERPOLATOR_FOH)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2016-01-05 17:46:28 +01:00
|
|
|
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown inter (%d)", in_inter);
|
2015-12-01 14:55:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (operation != CELL_GCM_TRANSFER_OPERATION_SRCCOPY)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown operation (%d)", operation);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2015-12-01 14:55:15 +01:00
|
|
|
u16 dst_color_format;
|
2016-01-05 17:46:28 +01:00
|
|
|
u32 out_pitch = 0;
|
|
|
|
|
u32 out_aligment = 64;
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
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];
|
2015-12-01 14:55:15 +01:00
|
|
|
dst_color_format = method_registers[NV3062_SET_COLOR_FORMAT];
|
2016-01-05 17:46:28 +01:00
|
|
|
out_pitch = method_registers[NV3062_SET_PITCH] >> 16;
|
|
|
|
|
out_aligment = method_registers[NV3062_SET_PITCH] & 0xffff;
|
2015-10-11 22:00:51 +02:00
|
|
|
break;
|
2014-06-03 00:17:33 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
case CELL_GCM_CONTEXT_SWIZZLE2D:
|
|
|
|
|
dst_dma = method_registers[NV309E_SET_CONTEXT_DMA_IMAGE];
|
|
|
|
|
dst_offset = method_registers[NV309E_SET_OFFSET];
|
2015-12-01 14:55:15 +01:00
|
|
|
dst_color_format = method_registers[NV309E_SET_FORMAT];
|
2015-10-11 22:00:51 +02:00
|
|
|
break;
|
2014-06-03 00:17:33 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
default:
|
|
|
|
|
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_context_surface (0x%x)", method_registers[NV3089_SET_CONTEXT_SURFACE]);
|
2016-01-05 17:46:28 +01:00
|
|
|
return;
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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)
|
2015-10-14 21:34:26 +02:00
|
|
|
{
|
2016-01-05 17:46:28 +01:00
|
|
|
out_pitch = out_bpp * out_w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (in_pitch == 0)
|
|
|
|
|
{
|
|
|
|
|
in_pitch = in_bpp * in_w;
|
2015-10-14 21:34:26 +02:00
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
if (clip_w > out_w)
|
|
|
|
|
{
|
|
|
|
|
clip_w = out_w;
|
|
|
|
|
}
|
2014-12-28 01:35:56 +01:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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::_ptr<u8>(src_address);
|
|
|
|
|
u8* pixels_dst = vm::_ptr<u8>(dst_address);
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-12-01 14:55:15 +01:00
|
|
|
if (dst_color_format != CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 &&
|
|
|
|
|
dst_color_format != CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2015-12-01 14:55:15 +01:00
|
|
|
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown dst_color_format (%d)", dst_color_format);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-12-01 14:55:15 +01:00
|
|
|
if (src_color_format != CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 &&
|
|
|
|
|
src_color_format != CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8)
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2015-12-01 14:55:15 +01:00
|
|
|
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown src_color_format (%d)", src_color_format);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
//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]);
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-12-01 14:55:15 +01:00
|
|
|
std::unique_ptr<u8[]> temp1, temp2;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
u32 out_offset = out_x * out_bpp + out_pitch * out_y;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
u32 slice_h = (u32)(clip_h * (method_registers[NV3089_DS_DX] / 1048576.f));
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
if (slice_h)
|
|
|
|
|
{
|
|
|
|
|
if (clip_h < out_h)
|
|
|
|
|
{
|
|
|
|
|
--slice_h;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
slice_h = clip_h;
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-05 17:46:28 +01:00
|
|
|
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
|
2015-12-01 14:55:15 +01:00
|
|
|
{
|
2016-01-05 17:46:28 +01:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 14:55:15 +01:00
|
|
|
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;
|
2015-12-11 17:59:11 +01:00
|
|
|
u16 sw_height = 1 << sw_height_log2;
|
2015-12-01 14:55:15 +01:00
|
|
|
|
2015-12-11 17:59:11 +01:00
|
|
|
temp2.reset(new u8[out_bpp * sw_width * sw_height]);
|
2015-12-01 14:55:15 +01:00
|
|
|
|
|
|
|
|
u8* linear_pixels = pixels_src;
|
2015-12-11 17:59:11 +01:00
|
|
|
u8* swizzled_pixels = temp2.get();
|
2015-12-01 14:55:15 +01:00
|
|
|
|
|
|
|
|
// Check and pad texture out if we are given non square texture for swizzle to be correct
|
2015-12-11 17:59:11 +01:00
|
|
|
if (sw_width != out_w || sw_height != out_h)
|
2015-12-02 10:44:56 +01:00
|
|
|
{
|
2016-01-05 17:46:28 +01:00
|
|
|
std::unique_ptr<u8[]> sw_temp(new u8[out_bpp * sw_width * sw_height]);
|
2015-12-01 14:55:15 +01:00
|
|
|
|
2015-12-11 17:59:11 +01:00
|
|
|
switch (out_bpp)
|
2015-12-02 10:44:56 +01:00
|
|
|
{
|
2015-12-01 14:55:15 +01:00
|
|
|
case 1:
|
2015-12-11 17:59:11 +01:00
|
|
|
pad_texture<u8>(linear_pixels, sw_temp.get(), out_w, out_h, sw_width, sw_height);
|
2015-12-01 14:55:15 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
2015-12-11 17:59:11 +01:00
|
|
|
pad_texture<u16>(linear_pixels, sw_temp.get(), out_w, out_h, sw_width, sw_height);
|
2015-12-01 14:55:15 +01:00
|
|
|
break;
|
|
|
|
|
case 4:
|
2015-12-11 17:59:11 +01:00
|
|
|
pad_texture<u32>(linear_pixels, sw_temp.get(), out_w, out_h, sw_width, sw_height);
|
2015-12-01 14:55:15 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2015-12-11 17:59:11 +01:00
|
|
|
|
|
|
|
|
linear_pixels = sw_temp.get();
|
2015-12-01 14:55:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
namespace nv0039
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
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)
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
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])),
|
2015-10-11 22:00:51 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
void flip_command(thread* rsx, u32 arg)
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-11-06 00:56:27 +01:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx->gcm_current_buffer = arg;
|
|
|
|
|
rsx->flip(arg);
|
2015-11-09 22:27:33 +01:00
|
|
|
// 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();
|
2014-12-01 23:02:05 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx->last_flip_time = get_system_time() - 1000000;
|
|
|
|
|
rsx->gcm_current_buffer = arg;
|
|
|
|
|
rsx->flip_status = 0;
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
if (rsx->flip_handler)
|
2014-12-01 23:02:05 +01:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
Emu.GetCallbackManager().Async([func = rsx->flip_handler](PPUThread& ppu)
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
func(ppu, 1);
|
2015-10-09 20:04:20 +02:00
|
|
|
});
|
2014-12-01 23:02:05 +01:00
|
|
|
}
|
2014-06-03 00:17:33 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
rsx->sem_flip.post_and_wait();
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
//sync
|
|
|
|
|
double limit;
|
2015-10-26 22:09:31 +01:00
|
|
|
switch (rpcs3::state.config.rsx.frame_limit.value())
|
2014-06-03 00:17:33 +02:00
|
|
|
{
|
2015-10-26 22:09:31 +01:00
|
|
|
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
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-26 22:09:31 +01:00
|
|
|
case rsx_frame_limit::Off:
|
2015-10-11 22:00:51 +02:00
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec())));
|
|
|
|
|
rsx->timer_sync.Start();
|
2015-10-31 18:19:45 +01:00
|
|
|
rsx->local_transform_constants.clear();
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-14 21:34:26 +02:00
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
struct __rsx_methods_t
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
using rsx_impl_method_t = void(*)(u32);
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
template<rsx_method_t impl_func>
|
|
|
|
|
force_inline static void call_impl_func(thread *rsx, u32 arg)
|
2014-12-26 21:15:00 +01:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
impl_func(rsx, arg);
|
2014-12-26 21:15:00 +01:00
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
template<rsx_impl_method_t impl_func>
|
|
|
|
|
force_inline static void call_impl_func(thread *rsx, u32 arg)
|
2014-12-26 06:59:47 +01:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
impl_func(arg);
|
2014-12-26 06:59:47 +01:00
|
|
|
}
|
2014-07-01 01:57:49 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
template<int id, typename T, T impl_func>
|
|
|
|
|
static void wrapper(thread *rsx, u32 arg)
|
2014-12-26 06:59:47 +01:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
// try process using gpu
|
2015-11-26 09:06:29 +01:00
|
|
|
if (rsx->do_method(id, arg))
|
2015-11-06 00:56:27 +01:00
|
|
|
{
|
|
|
|
|
if (rsx->capture_current_frame && id == NV4097_CLEAR_SURFACE)
|
2015-11-09 23:57:35 +01:00
|
|
|
rsx->capture_frame("clear");
|
2015-10-11 22:00:51 +02:00
|
|
|
return;
|
2015-11-06 00:56:27 +01:00
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
// not handled by renderer
|
|
|
|
|
// try process using cpu
|
|
|
|
|
if (impl_func != nullptr)
|
|
|
|
|
call_impl_func<impl_func>(rsx, arg);
|
2014-12-26 06:59:47 +01:00
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
template<int id, int step, int count, template<u32> class T, int index = 0>
|
|
|
|
|
struct bind_range_impl_t
|
2015-10-04 00:45:26 +02:00
|
|
|
{
|
2015-10-13 19:44:58 +02:00
|
|
|
force_inline static void impl()
|
|
|
|
|
{
|
|
|
|
|
bind_range_impl_t<id + step, step, count, T, index + 1>::impl();
|
2015-10-13 21:59:25 +02:00
|
|
|
bind<id, T<index>::impl>();
|
2015-10-13 19:44:58 +02:00
|
|
|
}
|
|
|
|
|
};
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
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()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-13 19:44:58 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2014-07-01 01:57:49 +02:00
|
|
|
|
2015-12-02 10:23:25 +01:00
|
|
|
[[noreturn]] never_inline static void bind_redefinition_error(int id)
|
|
|
|
|
{
|
|
|
|
|
throw EXCEPTION("RSX method implementation redefinition (0x%04x)", id);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
template<int id, typename T, T impl_func>
|
|
|
|
|
static void bind_impl()
|
|
|
|
|
{
|
|
|
|
|
if (methods[id])
|
|
|
|
|
{
|
2015-12-02 10:23:25 +01:00
|
|
|
bind_redefinition_error(id);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2014-07-01 01:57:49 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
methods[id] = wrapper<id, T, impl_func>;
|
|
|
|
|
}
|
2015-01-31 14:01:34 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
template<int id, typename T, T impl_func>
|
|
|
|
|
static void bind_cpu_only_impl()
|
|
|
|
|
{
|
|
|
|
|
if (methods[id])
|
|
|
|
|
{
|
2015-12-02 10:23:25 +01:00
|
|
|
bind_redefinition_error(id);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
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>(); }
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
__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>();
|
2015-12-31 19:15:44 +01:00
|
|
|
bind<NV4097_INLINE_ARRAY, nv4097::draw_inline_array>();
|
2015-10-13 19:44:58 +02:00
|
|
|
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>();
|
2015-11-12 18:13:28 +01:00
|
|
|
bind_range<NV4097_SET_TRANSFORM_CONSTANT, 1, 32, nv4097::set_transform_constant>();
|
2015-10-13 19:44:58 +02:00
|
|
|
bind_range<NV4097_SET_TRANSFORM_PROGRAM + 3, 4, 128, nv4097::set_transform_program>();
|
2015-10-11 22:00:51 +02:00
|
|
|
bind_cpu_only<NV4097_GET_REPORT, nv4097::get_report>();
|
|
|
|
|
bind_cpu_only<NV4097_CLEAR_REPORT_VALUE, nv4097::clear_report_value>();
|
|
|
|
|
|
|
|
|
|
//NV308A
|
2015-11-26 09:13:33 +01:00
|
|
|
bind_range<NV308A_COLOR, 1, 256, nv308a::color>();
|
|
|
|
|
bind_range<NV308A_COLOR + 256, 1, 512, nv308a::color, 256>();
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
//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>();
|
2015-10-14 21:34:26 +02:00
|
|
|
bind_cpu_only<GCM_SET_USER_COMMAND, user_command>();
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
} __rsx_methods;
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-12-22 20:24:35 +01:00
|
|
|
std::string shaders_cache::path_to_root()
|
|
|
|
|
{
|
|
|
|
|
return fs::get_executable_dir() + "data/";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void shaders_cache::load(const std::string &path, shader_language lang)
|
|
|
|
|
{
|
|
|
|
|
std::string lang_name = convert::to<std::string>(lang);
|
|
|
|
|
|
|
|
|
|
auto extract_hash = [](const std::string &string)
|
|
|
|
|
{
|
|
|
|
|
return std::stoull(string.substr(0, string.find('.')).c_str(), 0, 16);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const fs::dir::entry &entry : fs::dir{ path })
|
|
|
|
|
{
|
|
|
|
|
if (entry.name == "." || entry.name == "..")
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
u64 hash;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
hash = extract_hash(entry.name);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(RSX, "Cache file '%s' ignored", entry.name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fmt::match(entry.name, "*.fs." + lang_name))
|
|
|
|
|
{
|
|
|
|
|
fs::file file{ path + entry.name };
|
|
|
|
|
decompiled_fragment_shaders.insert(hash, { (const std::string)file });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fmt::match(entry.name, "*.vs." + lang_name))
|
|
|
|
|
{
|
|
|
|
|
fs::file file{ path + entry.name };
|
|
|
|
|
decompiled_vertex_shaders.insert(hash, { (const std::string)file });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void shaders_cache::load(shader_language lang)
|
|
|
|
|
{
|
|
|
|
|
std::string root = path_to_root();
|
|
|
|
|
|
|
|
|
|
//shared cache
|
|
|
|
|
load(root + "cache/", lang);
|
|
|
|
|
|
|
|
|
|
std::string title_id = Emu.GetTitleID();
|
|
|
|
|
|
|
|
|
|
if (!title_id.empty())
|
|
|
|
|
{
|
|
|
|
|
load(root + title_id + "/cache/", lang);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 get_address(u32 offset, u32 location)
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 res = 0;
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
switch (location)
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
|
|
|
|
|
case CELL_GCM_LOCATION_LOCAL:
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
//TODO: don't use not named constants like 0xC0000000
|
|
|
|
|
res = 0xC0000000 + offset;
|
|
|
|
|
break;
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
|
|
|
|
|
case CELL_GCM_LOCATION_MAIN:
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
res = (u32)RSXIOMem.RealAddr(offset); // TODO: Error Check?
|
|
|
|
|
if (res == 0)
|
|
|
|
|
{
|
2015-10-14 21:34:26 +02:00
|
|
|
throw EXCEPTION("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped", offset, location);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
//if (Emu.GetGSManager().GetRender().strict_ordering[offset >> 20])
|
|
|
|
|
//{
|
|
|
|
|
// _mm_mfence(); // probably doesn't have any effect on current implementation
|
|
|
|
|
//}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
break;
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
default:
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
throw EXCEPTION("Invalid location (offset=0x%x, location=0x%x)", offset, location);
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
return res;
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 get_vertex_type_size(u32 type)
|
2014-07-01 01:57:49 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
switch (type)
|
2015-02-08 23:44:55 +01:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
case CELL_GCM_VERTEX_S1: return sizeof(u16);
|
|
|
|
|
case CELL_GCM_VERTEX_F: return sizeof(f32);
|
|
|
|
|
case CELL_GCM_VERTEX_SF: return sizeof(f16);
|
|
|
|
|
case CELL_GCM_VERTEX_UB: return sizeof(u8);
|
|
|
|
|
case CELL_GCM_VERTEX_S32K: return sizeof(u32);
|
|
|
|
|
case CELL_GCM_VERTEX_CMP: return sizeof(u32);
|
|
|
|
|
case CELL_GCM_VERTEX_UB256: return sizeof(u8) * 4;
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
default:
|
|
|
|
|
LOG_ERROR(RSX, "RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", type);
|
|
|
|
|
assert(0);
|
|
|
|
|
return 1;
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2014-07-01 01:57:49 +02:00
|
|
|
}
|
2016-01-05 17:26:44 +01:00
|
|
|
|
2016-01-05 21:55:43 +01:00
|
|
|
void tiled_region::write(const void *src, u32 width, u32 height, u32 pitch)
|
2016-01-05 17:26:44 +01:00
|
|
|
{
|
|
|
|
|
if (!tile)
|
|
|
|
|
{
|
|
|
|
|
memcpy(ptr, src, height * pitch);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 offset_x = base % tile->pitch;
|
|
|
|
|
u32 offset_y = base / tile->pitch;
|
|
|
|
|
|
|
|
|
|
switch (tile->comp)
|
|
|
|
|
{
|
|
|
|
|
case CELL_GCM_COMPMODE_C32_2X1:
|
|
|
|
|
case CELL_GCM_COMPMODE_DISABLED:
|
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
|
|
|
{
|
|
|
|
|
memcpy(ptr + (offset_y + y) * tile->pitch + offset_x, (u8*)src + pitch * y, pitch);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
/*
|
|
|
|
|
case CELL_GCM_COMPMODE_C32_2X1:
|
|
|
|
|
for (u32 y = 0; y < height; ++y)
|
|
|
|
|
{
|
|
|
|
|
for (u32 x = 0; x < width; ++x)
|
|
|
|
|
{
|
|
|
|
|
u32 value = *(u32*)((u8*)src + pitch * y + x * sizeof(u32));
|
|
|
|
|
|
|
|
|
|
*(u32*)(ptr + (offset_y + y) * tile->pitch + offset_x + (x * 2 + 0) * sizeof(u32)) = value;
|
|
|
|
|
*(u32*)(ptr + (offset_y + y) * tile->pitch + offset_x + (x * 2 + 1) * sizeof(u32)) = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
*/
|
|
|
|
|
case CELL_GCM_COMPMODE_C32_2X2:
|
|
|
|
|
for (u32 y = 0; y < height; ++y)
|
|
|
|
|
{
|
|
|
|
|
for (u32 x = 0; x < width; ++x)
|
|
|
|
|
{
|
|
|
|
|
u32 value = *(u32*)((u8*)src + pitch * y + x * sizeof(u32));
|
|
|
|
|
|
|
|
|
|
*(u32*)(ptr + (offset_y + y * 2 + 0) * tile->pitch + offset_x + (x * 2 + 0) * sizeof(u32)) = value;
|
|
|
|
|
*(u32*)(ptr + (offset_y + y * 2 + 0) * tile->pitch + offset_x + (x * 2 + 1) * sizeof(u32)) = value;
|
|
|
|
|
*(u32*)(ptr + (offset_y + y * 2 + 1) * tile->pitch + offset_x + (x * 2 + 0) * sizeof(u32)) = value;
|
|
|
|
|
*(u32*)(ptr + (offset_y + y * 2 + 1) * tile->pitch + offset_x + (x * 2 + 1) * sizeof(u32)) = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-05 21:55:43 +01:00
|
|
|
void tiled_region::read(void *dst, u32 width, u32 height, u32 pitch)
|
2016-01-05 17:26:44 +01:00
|
|
|
{
|
|
|
|
|
if (!tile)
|
|
|
|
|
{
|
|
|
|
|
memcpy(dst, ptr, height * pitch);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 offset_x = base % tile->pitch;
|
|
|
|
|
u32 offset_y = base / tile->pitch;
|
|
|
|
|
|
|
|
|
|
switch (tile->comp)
|
|
|
|
|
{
|
|
|
|
|
case CELL_GCM_COMPMODE_C32_2X1:
|
|
|
|
|
case CELL_GCM_COMPMODE_DISABLED:
|
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
|
|
|
{
|
|
|
|
|
memcpy((u8*)dst + pitch * y, ptr + (offset_y + y) * tile->pitch + offset_x, pitch);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
/*
|
|
|
|
|
case CELL_GCM_COMPMODE_C32_2X1:
|
|
|
|
|
for (u32 y = 0; y < height; ++y)
|
|
|
|
|
{
|
|
|
|
|
for (u32 x = 0; x < width; ++x)
|
|
|
|
|
{
|
|
|
|
|
u32 value = *(u32*)(ptr + (offset_y + y) * tile->pitch + offset_x + (x * 2 + 0) * sizeof(u32));
|
|
|
|
|
|
|
|
|
|
*(u32*)((u8*)dst + pitch * y + x * sizeof(u32)) = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
*/
|
|
|
|
|
case CELL_GCM_COMPMODE_C32_2X2:
|
|
|
|
|
for (u32 y = 0; y < height; ++y)
|
|
|
|
|
{
|
|
|
|
|
for (u32 x = 0; x < width; ++x)
|
|
|
|
|
{
|
|
|
|
|
u32 value = *(u32*)(ptr + (offset_y + y * 2 + 0) * tile->pitch + offset_x + (x * 2 + 0) * sizeof(u32));
|
|
|
|
|
|
|
|
|
|
*(u32*)((u8*)dst + pitch * y + x * sizeof(u32)) = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-01 01:57:49 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
void thread::load_vertex_data(u32 first, u32 count)
|
2014-07-01 01:57:49 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
vertex_draw_count += count;
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
for (int index = 0; index < limits::vertex_count; ++index)
|
2015-08-16 17:37:20 +02:00
|
|
|
{
|
2015-10-14 19:47:09 +02:00
|
|
|
const auto &info = vertex_arrays_info[index];
|
2015-02-10 13:51:45 +01:00
|
|
|
|
2015-12-23 22:25:02 +01:00
|
|
|
if (info.size == 0) // disabled
|
2015-10-11 22:00:51 +02:00
|
|
|
continue;
|
2015-02-10 13:51:45 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
auto &data = vertex_arrays[index];
|
2015-02-10 13:51:45 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 type_size = get_vertex_type_size(info.type);
|
|
|
|
|
u32 element_size = type_size * info.size;
|
2015-02-08 23:44:55 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 dst_position = (u32)data.size();
|
|
|
|
|
data.resize(dst_position + count * element_size);
|
2015-10-14 19:47:09 +02:00
|
|
|
write_vertex_array_data_to_buffer(data.data() + dst_position, first, count, index, info);
|
2015-02-10 13:51:45 +01:00
|
|
|
}
|
2014-05-25 16:21:38 +02:00
|
|
|
}
|
2014-02-20 00:39:47 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
void thread::load_vertex_index_data(u32 first, u32 count)
|
2014-05-25 16:21:38 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 address = get_address(method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
|
|
|
|
u32 type = method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4;
|
2014-02-20 00:39:47 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 type_size = type == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 ? sizeof(u32) : sizeof(u16);
|
|
|
|
|
u32 dst_offset = (u32)vertex_index_array.size();
|
|
|
|
|
vertex_index_array.resize(dst_offset + count * type_size);
|
2015-10-09 20:04:20 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
u32 base_offset = method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET];
|
|
|
|
|
u32 base_index = method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX];
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
switch (type)
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
|
|
|
|
|
for (u32 i = 0; i < count; ++i)
|
2015-10-04 00:45:26 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
(u32&)vertex_index_array[dst_offset + i * sizeof(u32)] = vm::read32(address + (first + i) * sizeof(u32));
|
|
|
|
|
}
|
|
|
|
|
break;
|
2014-06-28 03:19:44 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
|
|
|
|
|
for (u32 i = 0; i < count; ++i)
|
|
|
|
|
{
|
|
|
|
|
(u16&)vertex_index_array[dst_offset + i * sizeof(u16)] = vm::read16(address + (first + i) * sizeof(u16));
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-11-09 23:57:35 +01:00
|
|
|
void thread::capture_frame(const std::string &name)
|
2015-11-06 00:56:27 +01:00
|
|
|
{
|
|
|
|
|
frame_capture_data::draw_state draw_state = {};
|
|
|
|
|
|
|
|
|
|
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
|
|
|
|
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
|
|
|
|
size_t pitch = clip_w * 4;
|
|
|
|
|
std::vector<size_t> color_index_to_record;
|
|
|
|
|
switch (method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
|
|
|
|
{
|
|
|
|
|
case CELL_GCM_SURFACE_TARGET_0:
|
|
|
|
|
color_index_to_record = { 0 };
|
|
|
|
|
break;
|
|
|
|
|
case CELL_GCM_SURFACE_TARGET_1:
|
|
|
|
|
color_index_to_record = { 1 };
|
|
|
|
|
break;
|
|
|
|
|
case CELL_GCM_SURFACE_TARGET_MRT1:
|
|
|
|
|
color_index_to_record = { 0, 1 };
|
|
|
|
|
break;
|
|
|
|
|
case CELL_GCM_SURFACE_TARGET_MRT2:
|
|
|
|
|
color_index_to_record = { 0, 1, 2 };
|
|
|
|
|
break;
|
|
|
|
|
case CELL_GCM_SURFACE_TARGET_MRT3:
|
|
|
|
|
color_index_to_record = { 0, 1, 2, 3 };
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-12-31 19:15:44 +01:00
|
|
|
/* for (size_t i : color_index_to_record)
|
2015-11-06 00:56:27 +01:00
|
|
|
{
|
|
|
|
|
draw_state.color_buffer[i].width = clip_w;
|
|
|
|
|
draw_state.color_buffer[i].height = clip_h;
|
|
|
|
|
draw_state.color_buffer[i].data.resize(pitch * clip_h);
|
|
|
|
|
copy_render_targets_to_memory(draw_state.color_buffer[i].data.data(), i);
|
|
|
|
|
}
|
|
|
|
|
if (get_address(method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], method_registers[NV4097_SET_CONTEXT_DMA_ZETA]))
|
|
|
|
|
{
|
|
|
|
|
draw_state.depth.width = clip_w;
|
|
|
|
|
draw_state.depth.height = clip_h;
|
|
|
|
|
draw_state.depth.data.resize(clip_w * clip_h * 4);
|
|
|
|
|
copy_depth_buffer_to_memory(draw_state.depth.data.data());
|
|
|
|
|
draw_state.stencil.width = clip_w;
|
|
|
|
|
draw_state.stencil.height = clip_h;
|
|
|
|
|
draw_state.stencil.data.resize(clip_w * clip_h * 4);
|
|
|
|
|
copy_stencil_buffer_to_memory(draw_state.stencil.data.data());
|
2015-12-31 19:15:44 +01:00
|
|
|
}*/
|
2015-11-10 18:59:15 +01:00
|
|
|
draw_state.programs = get_programs();
|
2015-11-09 23:57:35 +01:00
|
|
|
draw_state.name = name;
|
2015-11-06 00:56:27 +01:00
|
|
|
frame_debug.draw_calls.push_back(draw_state);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
void thread::begin()
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
draw_mode = method_registers[NV4097_SET_BEGIN_END];
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2015-01-31 14:01:34 +01:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
void thread::end()
|
|
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
vertex_index_array.clear();
|
|
|
|
|
for (auto &vertex_array : vertex_arrays)
|
|
|
|
|
vertex_array.clear();
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
transform_constants.clear();
|
2015-11-06 00:56:27 +01:00
|
|
|
|
|
|
|
|
if (capture_current_frame)
|
2015-11-09 23:57:35 +01:00
|
|
|
capture_frame("Draw " + std::to_string(vertex_draw_count));
|
2015-10-11 20:59:46 +02:00
|
|
|
}
|
2014-06-28 03:19:44 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
void thread::on_task()
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
on_init_thread();
|
2015-10-11 20:59:46 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
reset();
|
2014-06-28 03:19:44 +02:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
last_flip_time = get_system_time() - 1000000;
|
2014-06-28 03:19:44 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
scope_thread_t vblank(PURE_EXPR("VBlank Thread"s), [this]()
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 20:59:46 +02:00
|
|
|
const u64 start_time = get_system_time();
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
vblank_count = 0;
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
// TODO: exit condition
|
|
|
|
|
while (!Emu.IsStopped())
|
2015-10-09 20:04:20 +02:00
|
|
|
{
|
2015-10-11 20:59:46 +02:00
|
|
|
if (get_system_time() - start_time > vblank_count * 1000000 / 60)
|
2015-10-05 17:40:22 +02:00
|
|
|
{
|
2015-10-11 20:59:46 +02:00
|
|
|
vblank_count++;
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
if (vblank_handler)
|
2015-10-05 17:40:22 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
Emu.GetCallbackManager().Async([func = vblank_handler](PPUThread& ppu)
|
2015-10-11 20:59:46 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
func(ppu, 1);
|
2015-10-11 20:59:46 +02:00
|
|
|
});
|
|
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
continue;
|
2015-10-11 20:59:46 +02:00
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(1ms); // hack
|
2015-10-09 20:04:20 +02:00
|
|
|
}
|
2015-10-11 20:59:46 +02:00
|
|
|
});
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
// TODO: exit condition
|
|
|
|
|
while (true)
|
2015-10-11 20:59:46 +02:00
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
CHECK_EMU_STATUS;
|
2015-10-11 20:59:46 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
be_t<u32> get = ctrl->get;
|
|
|
|
|
be_t<u32> put = ctrl->put;
|
2015-10-11 20:59:46 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
if (put == get || !Emu.IsRunning())
|
|
|
|
|
{
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-10-11 20:59:46 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
const u32 cmd = ReadIO32(get);
|
|
|
|
|
const u32 count = (cmd >> 18) & 0x7ff;
|
2015-07-04 01:22:24 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
if (cmd & CELL_GCM_METHOD_FLAG_JUMP)
|
|
|
|
|
{
|
|
|
|
|
u32 offs = cmd & 0x1fffffff;
|
|
|
|
|
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
|
|
|
|
|
ctrl->get = offs;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (cmd & CELL_GCM_METHOD_FLAG_CALL)
|
|
|
|
|
{
|
|
|
|
|
m_call_stack.push(get + 4);
|
|
|
|
|
u32 offs = cmd & ~3;
|
|
|
|
|
//LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get);
|
|
|
|
|
ctrl->get = offs;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (cmd == CELL_GCM_METHOD_FLAG_RETURN)
|
|
|
|
|
{
|
|
|
|
|
u32 get = m_call_stack.top();
|
|
|
|
|
m_call_stack.pop();
|
|
|
|
|
//LOG_WARNING(RSX, "rsx return(0x%x)", get);
|
|
|
|
|
ctrl->get = get;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
if (cmd == 0) //nop
|
|
|
|
|
{
|
|
|
|
|
ctrl->get = get + 4;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-10-05 17:40:22 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
auto args = vm::ptr<u32>::make((u32)RSXIOMem.RealAddr(get + 4));
|
2015-10-05 17:40:22 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
u32 first_cmd = (cmd & 0xffff) >> 2;
|
2015-10-05 17:40:22 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
if (cmd & 0x3)
|
|
|
|
|
{
|
|
|
|
|
LOG_WARNING(Log::RSX, "unaligned command: %s (0x%x from 0x%x)", get_method_name(first_cmd).c_str(), first_cmd, cmd & 0xffff);
|
|
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
for (u32 i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
u32 reg = cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT ? first_cmd : first_cmd + i;
|
|
|
|
|
u32 value = args[i];
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
if (rpcs3::config.misc.log.rsx_logging.value())
|
2015-10-11 22:00:51 +02:00
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
LOG_NOTICE(Log::RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
method_registers[reg] = value;
|
|
|
|
|
if (capture_current_frame)
|
|
|
|
|
frame_debug.command_queue.push_back(std::make_pair(reg, value));
|
|
|
|
|
|
|
|
|
|
if (auto method = methods[reg])
|
|
|
|
|
method(this, value);
|
2015-10-11 22:00:51 +02:00
|
|
|
}
|
2014-07-10 02:13:04 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
ctrl->get = get + (count + 1) * 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
std::string thread::get_name() const
|
|
|
|
|
{
|
|
|
|
|
return "rsx::thread"s;
|
2015-10-11 20:59:46 +02:00
|
|
|
}
|
2014-02-16 09:56:58 +01:00
|
|
|
|
2015-12-17 18:31:27 +01:00
|
|
|
void thread::fill_scale_offset_data(void *buffer, bool is_d3d) const
|
2015-10-31 18:08:49 +01:00
|
|
|
{
|
|
|
|
|
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
|
|
|
|
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
|
|
|
|
|
|
|
|
|
float scale_x = (float&)rsx::method_registers[NV4097_SET_VIEWPORT_SCALE] / (clip_w / 2.f);
|
|
|
|
|
float offset_x = (float&)rsx::method_registers[NV4097_SET_VIEWPORT_OFFSET] - (clip_w / 2.f);
|
|
|
|
|
offset_x /= clip_w / 2.f;
|
|
|
|
|
|
2015-11-11 00:19:27 +01:00
|
|
|
float scale_y = (float&)rsx::method_registers[NV4097_SET_VIEWPORT_SCALE + 1] / (clip_h / 2.f);
|
|
|
|
|
float offset_y = ((float&)rsx::method_registers[NV4097_SET_VIEWPORT_OFFSET + 1] - (clip_h / 2.f));
|
2015-10-31 18:08:49 +01:00
|
|
|
offset_y /= clip_h / 2.f;
|
2015-11-11 00:19:27 +01:00
|
|
|
if (is_d3d) scale_y *= -1;
|
|
|
|
|
if (is_d3d) offset_y *= -1;
|
2015-10-31 18:08:49 +01:00
|
|
|
|
|
|
|
|
float scale_z = (float&)rsx::method_registers[NV4097_SET_VIEWPORT_SCALE + 2];
|
|
|
|
|
float offset_z = (float&)rsx::method_registers[NV4097_SET_VIEWPORT_OFFSET + 2];
|
2015-11-11 00:19:27 +01:00
|
|
|
if (!is_d3d) offset_z -= .5;
|
2015-10-31 18:08:49 +01:00
|
|
|
|
|
|
|
|
float one = 1.f;
|
|
|
|
|
|
|
|
|
|
stream_vector(buffer, (u32&)scale_x, 0, 0, (u32&)offset_x);
|
|
|
|
|
stream_vector((char*)buffer + 16, 0, (u32&)scale_y, 0, (u32&)offset_y);
|
|
|
|
|
stream_vector((char*)buffer + 32, 0, 0, (u32&)scale_z, (u32&)offset_z);
|
|
|
|
|
stream_vector((char*)buffer + 48, 0, 0, 0, (u32&)one);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-31 18:19:45 +01:00
|
|
|
/**
|
|
|
|
|
* Fill buffer with vertex program constants.
|
|
|
|
|
* Buffer must be at least 512 float4 wide.
|
|
|
|
|
*/
|
2015-12-17 18:31:27 +01:00
|
|
|
void thread::fill_vertex_program_constants_data(void *buffer)
|
2015-10-31 18:19:45 +01:00
|
|
|
{
|
|
|
|
|
for (const auto &entry : transform_constants)
|
|
|
|
|
local_transform_constants[entry.first] = entry.second;
|
|
|
|
|
for (const auto &entry : local_transform_constants)
|
|
|
|
|
stream_vector_from_memory((char*)buffer + entry.first * 4 * sizeof(float), (void*)entry.second.rgba);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-31 19:15:44 +01:00
|
|
|
void thread::write_inline_array_to_buffer(void *dst_buffer)
|
|
|
|
|
{
|
|
|
|
|
u8* src = reinterpret_cast<u8*>(inline_vertex_array.data());
|
|
|
|
|
u8* dst = (u8*)dst_buffer;
|
|
|
|
|
|
|
|
|
|
size_t bytes_written = 0;
|
|
|
|
|
while (bytes_written < inline_vertex_array.size() * sizeof(u32))
|
|
|
|
|
{
|
|
|
|
|
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
|
|
|
|
{
|
|
|
|
|
const auto &info = vertex_arrays_info[index];
|
|
|
|
|
|
|
|
|
|
if (!info.size) // disabled
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
u32 type_size = rsx::get_vertex_type_size(info.type);
|
|
|
|
|
u32 element_size = type_size * info.size;
|
|
|
|
|
|
|
|
|
|
if (type_size == 1 && info.size == 4)
|
|
|
|
|
{
|
|
|
|
|
dst[0] = src[3];
|
|
|
|
|
dst[1] = src[2];
|
|
|
|
|
dst[2] = src[1];
|
|
|
|
|
dst[3] = src[0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
memcpy(dst, src, element_size);
|
|
|
|
|
|
|
|
|
|
src += element_size;
|
|
|
|
|
dst += element_size;
|
|
|
|
|
|
|
|
|
|
bytes_written += element_size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
u64 thread::timestamp() const
|
|
|
|
|
{
|
|
|
|
|
// Get timestamp, and convert it from microseconds to nanoseconds
|
|
|
|
|
return get_system_time() * 1000;
|
|
|
|
|
}
|
2013-11-09 22:29:49 +01:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
void thread::reset()
|
|
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
//setup method registers
|
2015-09-26 22:46:04 +02:00
|
|
|
std::memset(method_registers, 0, sizeof(method_registers));
|
2015-10-11 22:00:51 +02:00
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_COLOR_MASK] = CELL_GCM_COLOR_MASK_R | CELL_GCM_COLOR_MASK_G | CELL_GCM_COLOR_MASK_B | CELL_GCM_COLOR_MASK_A;
|
|
|
|
|
method_registers[NV4097_SET_SCISSOR_HORIZONTAL] = (4096 << 16) | 0;
|
|
|
|
|
method_registers[NV4097_SET_SCISSOR_VERTICAL] = (4096 << 16) | 0;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_ALPHA_FUNC] = CELL_GCM_ALWAYS;
|
|
|
|
|
method_registers[NV4097_SET_ALPHA_REF] = 0;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_BLEND_FUNC_SFACTOR] = (CELL_GCM_ONE << 16) | CELL_GCM_ONE;
|
|
|
|
|
method_registers[NV4097_SET_BLEND_FUNC_DFACTOR] = (CELL_GCM_ZERO << 16) | CELL_GCM_ZERO;
|
|
|
|
|
method_registers[NV4097_SET_BLEND_COLOR] = 0;
|
|
|
|
|
method_registers[NV4097_SET_BLEND_COLOR2] = 0;
|
|
|
|
|
method_registers[NV4097_SET_BLEND_EQUATION] = (CELL_GCM_FUNC_ADD << 16) | CELL_GCM_FUNC_ADD;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_MASK] = 0xff;
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_FUNC] = CELL_GCM_ALWAYS;
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_FUNC_REF] = 0x00;
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_FUNC_MASK] = 0xff;
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_OP_FAIL] = CELL_GCM_KEEP;
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_OP_ZFAIL] = CELL_GCM_KEEP;
|
|
|
|
|
method_registers[NV4097_SET_STENCIL_OP_ZPASS] = CELL_GCM_KEEP;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_MASK] = 0xff;
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_FUNC] = CELL_GCM_ALWAYS;
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_FUNC_REF] = 0x00;
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_FUNC_MASK] = 0xff;
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_OP_FAIL] = CELL_GCM_KEEP;
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_OP_ZFAIL] = CELL_GCM_KEEP;
|
|
|
|
|
method_registers[NV4097_SET_BACK_STENCIL_OP_ZPASS] = CELL_GCM_KEEP;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_SHADE_MODE] = CELL_GCM_SMOOTH;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_LOGIC_OP] = CELL_GCM_COPY;
|
|
|
|
|
|
|
|
|
|
(f32&)method_registers[NV4097_SET_DEPTH_BOUNDS_MIN] = 0.f;
|
|
|
|
|
(f32&)method_registers[NV4097_SET_DEPTH_BOUNDS_MAX] = 1.f;
|
|
|
|
|
|
|
|
|
|
(f32&)method_registers[NV4097_SET_CLIP_MIN] = 0.f;
|
|
|
|
|
(f32&)method_registers[NV4097_SET_CLIP_MAX] = 1.f;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_LINE_WIDTH] = 1 << 3;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_FOG_MODE] = CELL_GCM_FOG_MODE_EXP;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_DEPTH_FUNC] = CELL_GCM_LESS;
|
|
|
|
|
method_registers[NV4097_SET_DEPTH_MASK] = CELL_GCM_TRUE;
|
|
|
|
|
(f32&)method_registers[NV4097_SET_POLYGON_OFFSET_SCALE_FACTOR] = 0.f;
|
|
|
|
|
(f32&)method_registers[NV4097_SET_POLYGON_OFFSET_BIAS] = 0.f;
|
|
|
|
|
method_registers[NV4097_SET_FRONT_POLYGON_MODE] = CELL_GCM_POLYGON_MODE_FILL;
|
|
|
|
|
method_registers[NV4097_SET_BACK_POLYGON_MODE] = CELL_GCM_POLYGON_MODE_FILL;
|
|
|
|
|
method_registers[NV4097_SET_CULL_FACE] = CELL_GCM_BACK;
|
|
|
|
|
method_registers[NV4097_SET_FRONT_FACE] = CELL_GCM_CCW;
|
|
|
|
|
method_registers[NV4097_SET_RESTART_INDEX] = -1;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_CLEAR_RECT_HORIZONTAL] = (4096 << 16) | 0;
|
|
|
|
|
method_registers[NV4097_SET_CLEAR_RECT_VERTICAL] = (4096 << 16) | 0;
|
|
|
|
|
|
|
|
|
|
method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] = 0xffffffff;
|
|
|
|
|
|
2015-12-23 22:25:02 +01:00
|
|
|
// Reset vertex attrib array
|
|
|
|
|
for (int i = 0; i < limits::vertex_count; i++)
|
|
|
|
|
vertex_arrays_info[i].size = 0;
|
|
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
// Construct Textures
|
|
|
|
|
for (int i = 0; i < limits::textures_count; i++)
|
2015-10-11 20:59:46 +02:00
|
|
|
{
|
|
|
|
|
textures[i].init(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-23 02:16:54 +02:00
|
|
|
|
2015-10-11 22:00:51 +02:00
|
|
|
void thread::init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
|
2015-10-11 20:59:46 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
ctrl = vm::_ptr<CellGcmControl>(ctrlAddress);
|
2015-10-11 20:59:46 +02:00
|
|
|
this->ioAddress = ioAddress;
|
2015-10-11 22:00:51 +02:00
|
|
|
this->ioSize = ioSize;
|
2015-10-11 20:59:46 +02:00
|
|
|
local_mem_addr = localAddress;
|
2015-10-11 22:00:51 +02:00
|
|
|
flip_status = 0;
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
m_used_gcm_commands.clear();
|
2014-08-23 02:16:54 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
on_init();
|
|
|
|
|
start();
|
2015-10-11 20:59:46 +02:00
|
|
|
}
|
2015-07-02 03:54:36 +02:00
|
|
|
|
2016-01-05 17:26:44 +01:00
|
|
|
GcmTileInfo *thread::find_tile(u32 offset, u32 location)
|
|
|
|
|
{
|
|
|
|
|
for (GcmTileInfo &tile : tiles)
|
|
|
|
|
{
|
|
|
|
|
if (!tile.binded || tile.location != location)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (offset >= tile.offset && offset < tile.offset + tile.size)
|
|
|
|
|
{
|
|
|
|
|
return &tile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-05 21:55:43 +01:00
|
|
|
tiled_region thread::get_tiled_address(u32 offset, u32 location)
|
2016-01-05 17:26:44 +01:00
|
|
|
{
|
|
|
|
|
u32 address = get_address(offset, location);
|
|
|
|
|
|
|
|
|
|
GcmTileInfo *tile = find_tile(offset, location);
|
|
|
|
|
u32 base = 0;
|
|
|
|
|
|
|
|
|
|
if (tile)
|
|
|
|
|
{
|
|
|
|
|
base = offset - tile->offset;
|
|
|
|
|
address = get_address(tile->offset, location);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return{ address, base, tile, (u8*)vm::base(address) };
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
u32 thread::ReadIO32(u32 addr)
|
2014-08-28 18:29:05 +02:00
|
|
|
{
|
2015-10-11 20:59:46 +02:00
|
|
|
u32 value;
|
2015-10-11 22:00:51 +02:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
if (!RSXIOMem.Read32(addr, &value))
|
|
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
throw EXCEPTION("%s(addr=0x%x): RSXIO memory not mapped", __FUNCTION__, addr);
|
2015-10-11 20:59:46 +02:00
|
|
|
}
|
2015-10-04 00:45:26 +02:00
|
|
|
|
2015-10-11 20:59:46 +02:00
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void thread::WriteIO32(u32 addr, u32 value)
|
2014-08-28 18:29:05 +02:00
|
|
|
{
|
2015-10-11 20:59:46 +02:00
|
|
|
if (!RSXIOMem.Write32(addr, value))
|
|
|
|
|
{
|
2015-10-11 22:00:51 +02:00
|
|
|
throw EXCEPTION("%s(addr=0x%x): RSXIO memory not mapped", __FUNCTION__, addr);
|
2015-10-11 20:59:46 +02:00
|
|
|
}
|
2014-08-28 18:29:05 +02:00
|
|
|
}
|
2014-12-20 18:14:27 +01:00
|
|
|
}
|