Skip to content

Commit 650452c

Browse files
committed
nv2a: Resolve overlapped dirty draws during 2d blit ops
1 parent 8c7de72 commit 650452c

File tree

6 files changed

+103
-42
lines changed

6 files changed

+103
-42
lines changed

hw/xbox/nv2a/pgraph/gl/blit.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ static void perform_blit(int operation, uint8_t *source, uint8_t *dest,
5353
}
5454
} else {
5555
fprintf(stderr, "Unknown blit operation: 0x%x\n", operation);
56-
assert(false && "Unknown blit operation");
56+
assert(!"Unknown blit operation");
5757
}
5858
}
5959

@@ -115,15 +115,13 @@ void pgraph_gl_image_blit(NV2AState *d)
115115
dest += context_surfaces->dest_offset;
116116
hwaddr dest_addr = dest - d->vram_ptr;
117117

118-
SurfaceBinding *surf_src = pgraph_gl_surface_get(d, source_addr);
119-
if (surf_src) {
120-
pgraph_gl_surface_download_if_dirty(d, surf_src);
121-
}
122-
123118
hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch +
124119
image_blit->in_x * bytes_per_pixel;
120+
source_addr += source_offset;
121+
125122
hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch +
126123
image_blit->out_x * bytes_per_pixel;
124+
dest_addr += dest_offset;
127125

128126
size_t max_row_pixels =
129127
MIN(context_surfaces->source_pitch, context_surfaces->dest_pitch) /
@@ -150,20 +148,12 @@ void pgraph_gl_image_blit(NV2AState *d)
150148
leftover_bytes = clipped_dest_size - consumed_bytes;
151149
}
152150

153-
SurfaceBinding *surf_dest = pgraph_gl_surface_get(d, dest_addr);
154-
if (surf_dest) {
155-
if (adjusted_height < surf_dest->height ||
156-
row_pixels < surf_dest->width) {
157-
pgraph_gl_surface_download_if_dirty(d, surf_dest);
158-
} else {
159-
// The blit will completely replace the surface so any pending
160-
// download should be discarded.
161-
surf_dest->download_pending = false;
162-
surf_dest->draw_dirty = false;
163-
}
164-
surf_dest->upload_pending = true;
165-
pg->draw_time++;
166-
}
151+
hwaddr source_size = adjusted_height * context_surfaces->source_pitch +
152+
image_blit->width * bytes_per_pixel;
153+
pgraph_gl_download_surfaces_in_range_if_dirty(pg, source_addr, source_size);
154+
155+
// TODO: just clear dirty_draw flag on surfaces that are fully overlapped.
156+
pgraph_gl_download_surfaces_in_range_if_dirty(pg, dest_addr, clipped_dest_size);
167157

168158
NV2A_DPRINTF(" blit 0x%tx -> 0x%tx (Size: %llu, Clipped Height: %zu)\n",
169159
source_addr, dest_addr, dest_size, adjusted_height);
@@ -215,9 +205,12 @@ void pgraph_gl_image_blit(NV2AState *d)
215205
}
216206
}
217207

218-
dest_addr += dest_offset;
219208
memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size,
220209
DIRTY_MEMORY_VGA);
221210
memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size,
222211
DIRTY_MEMORY_NV2A_TEX);
212+
213+
if (pgraph_gl_mark_surfaces_in_range_for_upload(d, dest_addr, dest_size)) {
214+
++pg->draw_time;
215+
}
223216
}

hw/xbox/nv2a/pgraph/gl/renderer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,11 @@ SurfaceBinding *pgraph_gl_surface_get(NV2AState *d, hwaddr addr);
284284
SurfaceBinding *pgraph_gl_surface_get_within(NV2AState *d, hwaddr addr);
285285
void pgraph_gl_surface_invalidate(NV2AState *d, SurfaceBinding *e);
286286
void pgraph_gl_unbind_surface(NV2AState *d, bool color);
287+
unsigned int pgraph_gl_mark_surfaces_in_range_for_upload(NV2AState *d,
288+
hwaddr start,
289+
hwaddr size);
290+
void pgraph_gl_download_surfaces_in_range_if_dirty(PGRAPHState *pg,
291+
hwaddr start, hwaddr size);
287292
void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface, bool force);
288293
void pgraph_gl_shader_cache_to_disk(ShaderBinding *snode);
289294
bool pgraph_gl_shader_load_from_memory(ShaderBinding *snode);

hw/xbox/nv2a/pgraph/gl/surface.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,50 @@ void pgraph_gl_surface_download_if_dirty(NV2AState *d,
632632
}
633633
}
634634

635+
unsigned int pgraph_gl_mark_surfaces_in_range_for_upload(NV2AState *d,
636+
hwaddr start,
637+
hwaddr size)
638+
{
639+
PGRAPHState *pg = &d->pgraph;
640+
PGRAPHGLState *r = pg->gl_renderer_state;
641+
642+
SurfaceBinding *surface;
643+
644+
hwaddr end = start + size - 1;
645+
646+
unsigned int num_marked = 0;
647+
QTAILQ_FOREACH (surface, &r->surfaces, entry) {
648+
hwaddr surf_end = surface->vram_addr + surface->size - 1;
649+
bool overlapping = !(surface->vram_addr >= end || start >= surf_end);
650+
if (overlapping) {
651+
surface->upload_pending = true;
652+
++num_marked;
653+
}
654+
}
655+
656+
return num_marked;
657+
}
658+
659+
660+
void pgraph_gl_download_surfaces_in_range_if_dirty(PGRAPHState *pg,
661+
hwaddr start, hwaddr size)
662+
{
663+
PGRAPHGLState *r = pg->gl_renderer_state;
664+
665+
SurfaceBinding *surface;
666+
667+
hwaddr end = start + size - 1;
668+
669+
QTAILQ_FOREACH (surface, &r->surfaces, entry) {
670+
hwaddr surf_end = surface->vram_addr + surface->size - 1;
671+
bool overlapping = !(surface->vram_addr >= end || start >= surf_end);
672+
if (overlapping) {
673+
pgraph_gl_surface_download_if_dirty(
674+
container_of(pg, NV2AState, pgraph), surface);
675+
}
676+
}
677+
}
678+
635679
static void bind_current_surface(NV2AState *d)
636680
{
637681
PGRAPHState *pg = &d->pgraph;

hw/xbox/nv2a/pgraph/vk/blit.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static void perform_blit(int operation, uint8_t *source, uint8_t *dest,
5757
}
5858
} else {
5959
fprintf(stderr, "Unknown blit operation: 0x%x\n", operation);
60-
assert(false && "Unknown blit operation");
60+
assert(!"Unknown blit operation");
6161
}
6262
}
6363

@@ -119,15 +119,13 @@ void pgraph_vk_image_blit(NV2AState *d)
119119
dest += context_surfaces->dest_offset;
120120
hwaddr dest_addr = dest - d->vram_ptr;
121121

122-
SurfaceBinding *surf_src = pgraph_vk_surface_get(d, source_addr);
123-
if (surf_src) {
124-
pgraph_vk_surface_download_if_dirty(d, surf_src);
125-
}
126-
127122
hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch +
128123
image_blit->in_x * bytes_per_pixel;
124+
source_addr += source_offset;
125+
129126
hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch +
130127
image_blit->out_x * bytes_per_pixel;
128+
dest_addr += dest_offset;
131129

132130
size_t max_row_pixels =
133131
MIN(context_surfaces->source_pitch, context_surfaces->dest_pitch) /
@@ -154,20 +152,12 @@ void pgraph_vk_image_blit(NV2AState *d)
154152
leftover_bytes = clipped_dest_size - consumed_bytes;
155153
}
156154

157-
SurfaceBinding *surf_dest = pgraph_vk_surface_get(d, dest_addr);
158-
if (surf_dest) {
159-
if (adjusted_height < surf_dest->height ||
160-
row_pixels < surf_dest->width) {
161-
pgraph_vk_surface_download_if_dirty(d, surf_dest);
162-
} else {
163-
// The blit will completely replace the surface so any pending
164-
// download should be discarded.
165-
surf_dest->download_pending = false;
166-
surf_dest->draw_dirty = false;
167-
}
168-
surf_dest->upload_pending = true;
169-
pg->draw_time++;
170-
}
155+
hwaddr source_size = adjusted_height * context_surfaces->source_pitch +
156+
image_blit->width * bytes_per_pixel;
157+
pgraph_vk_download_surfaces_in_range_if_dirty(pg, source_addr, source_size);
158+
159+
// TODO: just clear dirty_draw flag on surfaces that are fully overlapped.
160+
pgraph_vk_download_surfaces_in_range_if_dirty(pg, dest_addr, clipped_dest_size);
171161

172162
NV2A_DPRINTF(" blit 0x%tx -> 0x%tx (Size: %llu, Clipped Height: %zu)\n",
173163
source_addr, dest_addr, dest_size, adjusted_height);
@@ -219,9 +209,12 @@ void pgraph_vk_image_blit(NV2AState *d)
219209
}
220210
}
221211

222-
dest_addr += dest_offset;
223212
memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size,
224213
DIRTY_MEMORY_VGA);
225214
memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size,
226215
DIRTY_MEMORY_NV2A_TEX);
216+
217+
if (pgraph_vk_mark_surfaces_in_range_for_upload(d, dest_addr, dest_size)) {
218+
++pg->draw_time;
219+
}
227220
}

hw/xbox/nv2a/pgraph/vk/renderer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ void pgraph_vk_surface_download_if_dirty(NV2AState *d, SurfaceBinding *surface);
514514
SurfaceBinding *pgraph_vk_surface_get_within(NV2AState *d, hwaddr addr);
515515
void pgraph_vk_wait_for_surface_download(SurfaceBinding *e);
516516
void pgraph_vk_download_dirty_surfaces(NV2AState *d);
517+
unsigned int pgraph_vk_mark_surfaces_in_range_for_upload(NV2AState *d,
518+
hwaddr start,
519+
hwaddr size);
517520
void pgraph_vk_download_surfaces_in_range_if_dirty(PGRAPHState *pg, hwaddr start, hwaddr size);
518521
void pgraph_vk_upload_surface_data(NV2AState *d, SurfaceBinding *surface,
519522
bool force);

hw/xbox/nv2a/pgraph/vk/surface.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,29 @@ static void memcpy_image(void *dst, void const *src, int dst_stride,
122122
}
123123
}
124124

125+
unsigned int pgraph_vk_mark_surfaces_in_range_for_upload(NV2AState *d,
126+
hwaddr start,
127+
hwaddr size)
128+
{
129+
PGRAPHState *pg = &d->pgraph;
130+
PGRAPHVkState *r = pg->vk_renderer_state;
131+
SurfaceBinding *surface;
132+
133+
hwaddr end = start + size - 1;
134+
135+
unsigned int num_marked = 0;
136+
QTAILQ_FOREACH (surface, &r->surfaces, entry) {
137+
hwaddr surf_end = surface->vram_addr + surface->size - 1;
138+
bool overlapping = !(surface->vram_addr >= end || start >= surf_end);
139+
if (overlapping) {
140+
surface->upload_pending = true;
141+
++num_marked;
142+
}
143+
}
144+
145+
return num_marked;
146+
}
147+
125148
static bool check_surface_overlaps_range(const SurfaceBinding *surface,
126149
hwaddr range_start, hwaddr range_len)
127150
{

0 commit comments

Comments
 (0)