unittester: Implement 0x02 "Read Screen Snapshot Rectangle"
This will need some extra testing but it does appear to be at least somewhat functional.
This commit is contained in:
@@ -126,9 +126,7 @@ If there is no screen snapshot, then all values will be 0 as per the initial scr
|
||||
|
||||
### 0x02: Read Screen Snapshot Rectangle
|
||||
|
||||
**TODO: IMPLEMENT ME!**
|
||||
|
||||
Returns a rectangular snapshot of the screen snapshot buffer.
|
||||
Returns a rectangular snapshot of the screen snapshot buffer as an array of 32bpp 8:8:8:8 B:G:R:X pixels.
|
||||
|
||||
Input:
|
||||
|
||||
|
@@ -91,6 +91,13 @@ struct unittester_state {
|
||||
uint16_t snap_img_yoffs;
|
||||
|
||||
/* Command-specific state */
|
||||
/* 0x02: Read Screen Snapshot Rectangle */
|
||||
/* 0x03: Verify Screen Snapshot Rectangle */
|
||||
uint16_t read_snap_width;
|
||||
uint16_t read_snap_height;
|
||||
int16_t read_snap_xoffs;
|
||||
int16_t read_snap_yoffs;
|
||||
|
||||
/* 0x04: Exit */
|
||||
uint8_t exit_code;
|
||||
};
|
||||
@@ -157,6 +164,13 @@ unittester_write(uint16_t port, uint8_t val, UNUSED(void *priv))
|
||||
unittester.write_len = 1;
|
||||
break;
|
||||
|
||||
/* 0x02: Read Screen Snapshot Rectangle */
|
||||
case UT_CMD_READ_SCREEN_SNAPSHOT_RECTANGLE:
|
||||
unittester.cmd_id = UT_CMD_READ_SCREEN_SNAPSHOT_RECTANGLE;
|
||||
unittester.status = UT_STATUS_AWAITING_WRITE;
|
||||
unittester.write_len = 8;
|
||||
break;
|
||||
|
||||
/* 0x04: Exit */
|
||||
case UT_CMD_EXIT:
|
||||
unittester.cmd_id = UT_CMD_EXIT;
|
||||
@@ -200,6 +214,37 @@ unittester_write(uint16_t port, uint8_t val, UNUSED(void *priv))
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_CMD_READ_SCREEN_SNAPSHOT_RECTANGLE:
|
||||
switch(unittester.write_offs) {
|
||||
case 0:
|
||||
unittester.read_snap_width = (uint16_t)val;
|
||||
break;
|
||||
case 1:
|
||||
unittester.read_snap_width |= ((uint16_t)val) << 8;
|
||||
break;
|
||||
case 2:
|
||||
unittester.read_snap_height = (uint16_t)val;
|
||||
break;
|
||||
case 3:
|
||||
unittester.read_snap_height |= ((uint16_t)val) << 8;
|
||||
break;
|
||||
case 4:
|
||||
unittester.read_snap_xoffs = (uint16_t)val;
|
||||
break;
|
||||
case 5:
|
||||
unittester.read_snap_xoffs |= ((uint16_t)val) << 8;
|
||||
break;
|
||||
case 6:
|
||||
unittester.read_snap_yoffs = (uint16_t)val;
|
||||
break;
|
||||
case 7:
|
||||
unittester.read_snap_yoffs |= ((uint16_t)val) << 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* This should not be reachable, but just in case... */
|
||||
default:
|
||||
break;
|
||||
@@ -257,8 +302,8 @@ unittester_write(uint16_t port, uint8_t val, UNUSED(void *priv))
|
||||
unittester.snap_img_xoffs = (m->mon_overscan_x >> 1);
|
||||
unittester.snap_img_yoffs = (m->mon_overscan_y >> 1);
|
||||
/* Take snapshot */
|
||||
for (size_t y = 0; y < unittester.snap_img_height; y++) {
|
||||
for (size_t x = 0; x < unittester.snap_img_width; x++) {
|
||||
for (size_t y = 0; y < unittester.snap_overscan_height; y++) {
|
||||
for (size_t x = 0; x < unittester.snap_overscan_width; x++) {
|
||||
unittester_screen_buffer->line[y][x] = m->target_buffer->line[y][x];
|
||||
}
|
||||
}
|
||||
@@ -276,6 +321,32 @@ unittester_write(uint16_t port, uint8_t val, UNUSED(void *priv))
|
||||
unittester.read_len = 12;
|
||||
break;
|
||||
|
||||
case UT_CMD_READ_SCREEN_SNAPSHOT_RECTANGLE:
|
||||
/* Offset the X,Y offsets by the overscan offsets. */
|
||||
unittester.read_snap_xoffs += (int16_t)unittester.snap_img_xoffs;
|
||||
unittester.read_snap_yoffs += (int16_t)unittester.snap_img_yoffs;
|
||||
/*BUG: If the width and height are too large, this ends up with a multiplication overflow.
|
||||
In practice, this means we end up sending less than we would want to.
|
||||
However:
|
||||
- A width and height of that size is obscene, and goes beyond what one would reasonably want.
|
||||
- The consequences of triggering this bug are that one ends up with a bunch of FF FF FF FF pixels.
|
||||
- Special-casing this would add unnecessary complexity.
|
||||
So, this bug is kept here.
|
||||
If there is any need to fix this bug... then go and make the variables 64-bit :P
|
||||
*/
|
||||
unittester.read_len = ((uint32_t)unittester.read_snap_width) * ((uint32_t)unittester.read_snap_height) * 4;
|
||||
|
||||
/* Do we have anything to read? */
|
||||
if (unittester.read_len >= 1) {
|
||||
/* Yes - start reads! */
|
||||
unittester.status = UT_STATUS_AWAITING_READ;
|
||||
} else {
|
||||
/* No - stop here. */
|
||||
unittester.cmd_id = UT_CMD_NOOP;
|
||||
unittester.status = UT_STATUS_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Nothing to write? Stop here. */
|
||||
unittester.cmd_id = UT_CMD_NOOP;
|
||||
@@ -350,6 +421,25 @@ unittester_read(uint16_t port, UNUSED(void *priv))
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_CMD_READ_SCREEN_SNAPSHOT_RECTANGLE:
|
||||
/* WARNING: If the width is somehow 0 and wasn't caught earlier, you'll probably get a divide by zero crash. */
|
||||
{
|
||||
uint32_t idx = unittester.read_offs & 0x3;
|
||||
int32_t x = (unittester.read_offs >> 2) % unittester.read_snap_width;
|
||||
int32_t y = (unittester.read_offs >> 2) / unittester.read_snap_width;
|
||||
x += unittester.read_snap_xoffs;
|
||||
y += unittester.read_snap_yoffs;
|
||||
|
||||
if (x < 0 || y < 0 || x >= unittester.snap_overscan_width || y >= unittester.snap_overscan_height) {
|
||||
/* Out of range! */
|
||||
outval = (idx == 3 ? 0xFF : 0x00);
|
||||
} else {
|
||||
/* In range */
|
||||
outval = (unittester_screen_buffer->line[y][x] & 0x00FFFFFF)>>(idx*8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* This should not be reachable, but just in case... */
|
||||
default:
|
||||
break;
|
||||
|
Reference in New Issue
Block a user