Merge pull request #450 from refractionpcsx2/gs_download_v2

VIF/GS: Enhanced GS Download behaviour
This commit is contained in:
PSISP 2020-11-02 04:16:56 -05:00 committed by GitHub
commit 6fdbdf39e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 192 additions and 118 deletions

View file

@ -309,7 +309,10 @@ int DMAC::process_VIF1()
if (std::get<1>(quad_data))
store128(channels[VIF1].address, std::get<0>(quad_data));
else
{
arbitrate();
return count;
}
}
advance_source_dma(VIF1);
count++;

View file

@ -96,9 +96,10 @@ void VectorInterface::update(int cycles)
if (fifo_reverse)
{
vif_cmd_status = VIF_IDLE;
if (FIFO.size() <= (fifo_size - 4))
while (cycles--)
{
while (cycles--)
if (FIFO.size() <= (fifo_size - 4))
{
auto fifo_data = gif->read_GSFIFO();
//Check the GS still wants to send data
@ -108,7 +109,10 @@ void VectorInterface::update(int cycles)
for (int i = 0; i < 4; i++)
FIFO.push(std::get<0>(fifo_data)._u32[i]);
}
else
break;
}
return;
}
//Since the loop processes per-word, we need to multiply cycles by 4

View file

@ -494,9 +494,9 @@ void GraphicsInterface::send_PATH3_FIFO(uint128_t data)
}
}
std::tuple<uint128_t, uint32_t>GraphicsInterface::read_GSFIFO()
std::tuple<uint128_t, bool>GraphicsInterface::read_GSFIFO()
{
return gs->request_gs_download();
return gs->read_gs_download();
}
void GraphicsInterface::flush_path3_fifo()

View file

@ -88,7 +88,7 @@ class GraphicsInterface
void send_PATH2(uint32_t data[4]);
void send_PATH3(uint128_t quad);
void send_PATH3_FIFO(uint128_t quad);
std::tuple<uint128_t, uint32_t>read_GSFIFO();
std::tuple<uint128_t, bool>read_GSFIFO();
void intermittent_check();
@ -112,7 +112,7 @@ inline bool GraphicsInterface::path_active(int index, bool canInterruptPath3)
{
interrupt_path3(index);
}
return (active_path == index) && !gs->stalled() && !gif_temporary_stop;
return (active_path == index) && !gs->stalled() && !gif_temporary_stop && !gs->get_busdir();
}
inline void GraphicsInterface::resume_path3()

View file

@ -25,6 +25,7 @@ GraphicsSynthesizer::~GraphicsSynthesizer()
delete[] output_buffer1;
delete[] output_buffer2;
delete[] gs_download_buffer;
}
void GraphicsSynthesizer::reset()
@ -37,6 +38,12 @@ void GraphicsSynthesizer::reset()
if (!output_buffer2)
output_buffer2 = new uint32_t[1920 * 1280];
if (!gs_download_buffer)
gs_download_buffer = new uint128_t[(2048 * 2048) / 4];
gs_download_qwc = 0;
gs_download_addr = 0;
current_lock = std::unique_lock<std::mutex>();
using_first_buffer = true;
frame_count = 0;
@ -228,6 +235,9 @@ void GraphicsSynthesizer::write64_privileged(uint32_t addr, uint64_t value)
gs_thread.send_message({ GSCommand::write64_privileged_t,payload });
if (addr == 0x12001040 && !reg.BUSDIR && value)
request_gs_download();
bool old_IMR = reg.IMR.signal;
reg.write64_privileged(addr, value);
@ -246,6 +256,9 @@ void GraphicsSynthesizer::write32_privileged(uint32_t addr, uint32_t value)
gs_thread.send_message({ GSCommand::write32_privileged_t,payload });
if (addr == 0x12001040 && !reg.BUSDIR && value)
request_gs_download();
bool old_IMR = reg.IMR.signal;
reg.write32_privileged(addr, value);
//When SIGNAL is written to twice, the interrupt will not be processed until IMR.signal is flipped from 1 to 0.
@ -355,14 +368,48 @@ void GraphicsSynthesizer::wake_gs_thread()
gs_thread.wake_thread();
}
std::tuple<uint128_t, uint32_t>GraphicsSynthesizer::request_gs_download()
void GraphicsSynthesizer::request_gs_download()
{
GSMessagePayload payload;
payload.no_payload = {};
GSReturnMessage return_packet;
payload.download_payload = { gs_download_buffer, &download_mutex };
gs_thread.send_message({ GSCommand::request_local_host_tx, payload });
gs_thread.wake_thread();
GSReturnMessage data;
gs_thread.wait_for_return(GSReturn::local_host_transfer, data);
return std::make_tuple(data.payload.data_payload.quad_data, data.payload.data_payload.status);
gs_thread.wait_for_return(GSReturn::local_host_transfer, return_packet);
while (!download_mutex.try_lock())
{
printf("[GS] buffer 1 lock failed!\n");
std::this_thread::yield();
}
std::lock_guard<std::mutex> lock(download_mutex, std::adopt_lock);
gs_download_addr = 0;
gs_download_qwc = return_packet.payload.download_payload.quad_count;
}
std::tuple<uint128_t, bool>GraphicsSynthesizer::read_gs_download()
{
bool have_data;
uint128_t quad_data;
if (gs_download_qwc)
{
quad_data._u64[0] = gs_download_buffer[gs_download_addr]._u64[0];
quad_data._u64[1] = gs_download_buffer[gs_download_addr]._u64[1];
have_data = true;
gs_download_addr++;
gs_download_qwc--;
}
else
{
quad_data._u64[0] = 0;
quad_data._u64[1] = 0;
have_data = false;
}
return std::make_tuple(quad_data, have_data);
}

View file

@ -16,7 +16,10 @@ class GraphicsSynthesizer
int frame_count;
uint32_t* output_buffer1;
uint32_t* output_buffer2;//double buffered to prevent mutex lock
std::mutex output_buffer1_mutex, output_buffer2_mutex;
uint128_t* gs_download_buffer;
uint32_t gs_download_qwc;
uint32_t gs_download_addr;
std::mutex output_buffer1_mutex, output_buffer2_mutex, download_mutex;
bool using_first_buffer;
std::unique_lock<std::mutex> current_lock;
@ -65,6 +68,7 @@ class GraphicsSynthesizer
void send_message(GSMessage message);
void wake_gs_thread();
std::tuple<uint128_t, uint32_t>request_gs_download();
void request_gs_download();
std::tuple<uint128_t, bool>read_gs_download();
};
#endif // GS_HPP

View file

@ -402,9 +402,16 @@ void GraphicsSynthesizerThread::event_loop()
}
case request_local_host_tx:
{
auto p = data.payload.download_payload;
while (!p.target_mutex->try_lock())
{
printf("[GS_t] buffer lock failed!\n");
std::this_thread::yield();
}
std::lock_guard<std::mutex> lock(*p.target_mutex, std::adopt_lock);
GSReturnMessagePayload return_payload;
return_payload.data_payload.status = (TRXDIR != 3);
return_payload.data_payload.quad_data = local_to_host();
return_payload.download_payload.quad_count = local_to_host(p.target);
return_queue->push({ GSReturn::local_host_transfer, return_payload });
std::unique_lock<std::mutex> lk(data_mutex);
recieve_data = true;
@ -3055,21 +3062,23 @@ void GraphicsSynthesizerThread::write_HWREG(uint64_t data)
}
}
uint128_t GraphicsSynthesizerThread::local_to_host()
uint32_t GraphicsSynthesizerThread::local_to_host(uint128_t *target)
{
int ppd = 0; //pixels per doubleword (64-bits)
uint128_t return_data;
return_data._u64[0] = 0;
return_data._u64[1] = 0;
uint32_t return_qwc = 0;
target[0]._u64[0] = 0;
target[0]._u64[1] = 0;
printf("[GS_t] Local to Host transfer started\n");
if (TRXDIR == 3)
return return_data;
return return_qwc;
//Invalid transfer if no height/width has been set
if (TRXREG.width == 0 || TRXREG.height == 0)
{
TRXDIR = 3;
pixels_transferred = 0;
return return_data;
return return_qwc;
}
switch (BITBLTBUF.source_format)
@ -3109,103 +3118,105 @@ uint128_t GraphicsSynthesizerThread::local_to_host()
default:
Errors::die("[GS_t] GS Download Unrecognized BITBLTBUF source format $%02X\n", BITBLTBUF.source_format);
}
uint64_t data = 0;
for (int datapart = 0; datapart < 2; datapart++)
{
for (int i = 0; i < ppd; i++)
{
switch (BITBLTBUF.source_format)
{
case 0x00:
data |= (uint64_t)(read_PSMCT32_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFFFFFF) << (i * 32);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x01:
data = pack_PSMCT24(false);
break;
case 0x02:
data |= (uint64_t)(read_PSMCT16_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x0A:
data |= (uint64_t)(read_PSMCT16S_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x13:
data |= (uint64_t)(read_PSMCT8_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFF) << (i * 8);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x14:
data |= (uint64_t)(read_PSMCT4_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xf) << (i * 4);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x1B:
data |= (uint64_t)((read_PSMCT32_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) >> 24) & 0xFF) << (i * 8);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x30:
data |= (uint64_t)(read_PSMCT32Z_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFFFFFF) << (i * 32);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x31:
data = pack_PSMCT24(true);
break;
case 0x32:
data |= (uint64_t)(read_PSMCT16Z_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x3A:
data |= (uint64_t)(read_PSMCT16SZ_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
default:
Errors::die("[GS_t] GS Download Unrecognized BITBLTBUF source format $%02X\n", BITBLTBUF.source_format);
}
if (pixels_transferred % TRXREG.width == 0)
{
TRXPOS.int_source_x = TRXPOS.source_x;
TRXPOS.int_source_y++;
}
//Coordinates wrap at 2048 pixels
TRXPOS.int_source_x %= 2048;
TRXPOS.int_source_y %= 2048;
}
return_data._u64[datapart] = data;
data = 0;
}
int max_pixels = TRXREG.width * TRXREG.height;
if (pixels_transferred >= max_pixels)
while (pixels_transferred < max_pixels)
{
//Deactivate the transmisssion
printf("[GS_t] Local to Host transfer ended\n");
TRXDIR = 3;
pixels_transferred = 0;
uint64_t data = 0;
for (int datapart = 0; datapart < 2; datapart++)
{
for (int i = 0; i < ppd; i++)
{
switch (BITBLTBUF.source_format)
{
case 0x00:
data |= (uint64_t)(read_PSMCT32_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFFFFFF) << (i * 32);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x01:
data = pack_PSMCT24(false);
break;
case 0x02:
data |= (uint64_t)(read_PSMCT16_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x0A:
data |= (uint64_t)(read_PSMCT16S_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x13:
data |= (uint64_t)(read_PSMCT8_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFF) << (i * 8);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x14:
data |= (uint64_t)(read_PSMCT4_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xf) << (i * 4);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x1B:
data |= (uint64_t)((read_PSMCT32_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) >> 24) & 0xFF) << (i * 8);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x30:
data |= (uint64_t)(read_PSMCT32Z_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFFFFFF) << (i * 32);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x31:
data = pack_PSMCT24(true);
break;
case 0x32:
data |= (uint64_t)(read_PSMCT16Z_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
case 0x3A:
data |= (uint64_t)(read_PSMCT16SZ_block(BITBLTBUF.source_base, BITBLTBUF.source_width,
TRXPOS.int_source_x, TRXPOS.int_source_y) & 0xFFFF) << (i * 16);
pixels_transferred++;
TRXPOS.int_source_x++;
break;
default:
Errors::die("[GS_t] GS Download Unrecognized BITBLTBUF source format $%02X\n", BITBLTBUF.source_format);
}
if (pixels_transferred % TRXREG.width == 0)
{
TRXPOS.int_source_x = TRXPOS.source_x;
TRXPOS.int_source_y++;
}
//Coordinates wrap at 2048 pixels
TRXPOS.int_source_x %= 2048;
TRXPOS.int_source_y %= 2048;
}
target[return_qwc]._u64[datapart] = data;
data = 0;
}
return_qwc++;
}
return return_data;
//Deactivate the transmisssion
printf("[GS_t] Local to Host transfer ended\n");
TRXDIR = 3;
pixels_transferred = 0;
return return_qwc;
}
void GraphicsSynthesizerThread::unpack_PSMCT24(uint64_t data, int offset, bool z_format)

View file

@ -90,6 +90,11 @@ union GSMessagePayload
std::mutex* target_mutex;
} render_payload;
struct
{
uint128_t* target;
std::mutex* target_mutex;
} download_payload;
struct
{
std::ofstream* state;
} save_state_payload;
@ -136,9 +141,9 @@ union GSReturnMessagePayload
} no_payload;//C++ doesn't like the empty struct
struct
{
uint128_t quad_data;
uint32_t status;
} data_payload;
uint32_t quad_count;
} download_payload;
};
struct GSReturnMessage
@ -506,7 +511,7 @@ class GraphicsSynthesizerThread
float step_x0, float step_x1, float scx1, float scx2, TexLookupInfo& tex_info);
void render_sprite();
void write_HWREG(uint64_t data);
uint128_t local_to_host();
uint32_t local_to_host(uint128_t *target);
void unpack_PSMCT24(uint64_t data, int offset, bool z_format);
uint64_t pack_PSMCT24(bool z_format);
void local_to_local();