Skip to content

Commit 8e57422

Browse files
committed
nv2a: Resolve overlapped dirty draws during 2d blit ops
1 parent 196726b commit 8e57422

File tree

6 files changed

+103
-53
lines changed

6 files changed

+103
-53
lines changed

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

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,45 +70,32 @@ void pgraph_gl_image_blit(NV2AState *d)
7070
hwaddr source_addr = source - d->vram_ptr;
7171
hwaddr dest_addr = dest - d->vram_ptr;
7272

73-
SurfaceBinding *surf_src = pgraph_gl_surface_get(d, source_addr);
74-
if (surf_src) {
75-
pgraph_gl_surface_download_if_dirty(d, surf_src);
76-
}
77-
78-
SurfaceBinding *surf_dest = pgraph_gl_surface_get(d, dest_addr);
79-
if (surf_dest) {
80-
if (image_blit->height < surf_dest->height ||
81-
image_blit->width < surf_dest->width) {
82-
pgraph_gl_surface_download_if_dirty(d, surf_dest);
83-
} else {
84-
// The blit will completely replace the surface so any pending
85-
// download should be discarded.
86-
surf_dest->download_pending = false;
87-
surf_dest->draw_dirty = false;
88-
}
89-
surf_dest->upload_pending = true;
90-
pg->draw_time++;
91-
}
92-
9373
hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch +
9474
image_blit->in_x * bytes_per_pixel;
9575
hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch +
9676
image_blit->out_x * bytes_per_pixel;
9777

78+
source_addr += source_offset;
79+
dest_addr += dest_offset;
80+
9881
hwaddr source_size =
9982
(image_blit->height - 1) * context_surfaces->source_pitch +
10083
image_blit->width * bytes_per_pixel;
10184
hwaddr dest_size = (image_blit->height - 1) * context_surfaces->dest_pitch +
10285
image_blit->width * bytes_per_pixel;
10386

10487
/* FIXME: What does hardware do in this case? */
105-
assert(source_addr + source_offset + source_size <=
106-
memory_region_size(d->vram));
107-
assert(dest_addr + dest_offset + dest_size <= memory_region_size(d->vram));
88+
assert(source_addr + source_size <= memory_region_size(d->vram));
89+
assert(dest_addr + dest_size <= memory_region_size(d->vram));
10890

10991
uint8_t *source_row = source + source_offset;
11092
uint8_t *dest_row = dest + dest_offset;
11193

94+
pgraph_gl_download_surfaces_in_range_if_dirty(d, source_addr, source_size);
95+
96+
// TODO: just clear dirty_draw flag on surfaces that are fully overlapped.
97+
pgraph_gl_download_surfaces_in_range_if_dirty(d, dest_addr, dest_size);
98+
11299
if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) {
113100
// NV2A_GL_DPRINTF(false, "NV09F_SET_OPERATION_SRCCOPY");
114101
for (unsigned int y = 0; y < image_blit->height; y++) {
@@ -135,11 +122,9 @@ void pgraph_gl_image_blit(NV2AState *d)
135122
} else {
136123
fprintf(stderr, "Unknown blit operation: 0x%x\n",
137124
image_blit->operation);
138-
assert(false && "Unknown blit operation");
125+
assert(!"Unknown blit operation");
139126
}
140127

141-
NV2A_DPRINTF(" - 0x%tx -> 0x%tx\n", source_addr, dest_addr);
142-
143128
bool needs_alpha_patching;
144129
uint8_t alpha_override;
145130
switch (context_surfaces->color_format) {
@@ -166,9 +151,12 @@ void pgraph_gl_image_blit(NV2AState *d)
166151
}
167152
}
168153

169-
dest_addr += dest_offset;
170154
memory_region_set_client_dirty(d->vram, dest_addr, dest_size,
171155
DIRTY_MEMORY_VGA);
172156
memory_region_set_client_dirty(d->vram, dest_addr, dest_size,
173157
DIRTY_MEMORY_NV2A_TEX);
158+
159+
if (pgraph_gl_mark_surfaces_in_range_for_upload(d, dest_addr, dest_size)) {
160+
++pg->draw_time;
161+
}
174162
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ SurfaceBinding *pgraph_gl_surface_get(NV2AState *d, hwaddr addr);
279279
SurfaceBinding *pgraph_gl_surface_get_within(NV2AState *d, hwaddr addr);
280280
void pgraph_gl_surface_invalidate(NV2AState *d, SurfaceBinding *e);
281281
void pgraph_gl_unbind_surface(NV2AState *d, bool color);
282+
unsigned int pgraph_gl_mark_surfaces_in_range_for_upload(NV2AState *d,
283+
hwaddr start,
284+
hwaddr size);
285+
void pgraph_gl_download_surfaces_in_range_if_dirty(NV2AState *d, hwaddr start,
286+
hwaddr size);
282287
void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface, bool force);
283288
void pgraph_gl_shader_cache_to_disk(ShaderBinding *snode);
284289
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
@@ -628,6 +628,50 @@ void pgraph_gl_surface_download_if_dirty(NV2AState *d,
628628
}
629629
}
630630

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

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

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,45 +73,32 @@ void pgraph_vk_image_blit(NV2AState *d)
7373
hwaddr source_addr = source - d->vram_ptr;
7474
hwaddr dest_addr = dest - d->vram_ptr;
7575

76-
SurfaceBinding *surf_src = pgraph_vk_surface_get(d, source_addr);
77-
if (surf_src) {
78-
pgraph_vk_surface_download_if_dirty(d, surf_src);
79-
}
80-
81-
SurfaceBinding *surf_dest = pgraph_vk_surface_get(d, dest_addr);
82-
if (surf_dest) {
83-
if (image_blit->height < surf_dest->height ||
84-
image_blit->width < surf_dest->width) {
85-
pgraph_vk_surface_download_if_dirty(d, surf_dest);
86-
} else {
87-
// The blit will completely replace the surface so any pending
88-
// download should be discarded.
89-
surf_dest->download_pending = false;
90-
surf_dest->draw_dirty = false;
91-
}
92-
surf_dest->upload_pending = true;
93-
pg->draw_time++;
94-
}
95-
9676
hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch +
9777
image_blit->in_x * bytes_per_pixel;
9878
hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch +
9979
image_blit->out_x * bytes_per_pixel;
10080

81+
source_addr += source_offset;
82+
dest_addr += dest_offset;
83+
10184
hwaddr source_size =
10285
(image_blit->height - 1) * context_surfaces->source_pitch +
10386
image_blit->width * bytes_per_pixel;
10487
hwaddr dest_size = (image_blit->height - 1) * context_surfaces->dest_pitch +
10588
image_blit->width * bytes_per_pixel;
10689

10790
/* FIXME: What does hardware do in this case? */
108-
assert(source_addr + source_offset + source_size <=
109-
memory_region_size(d->vram));
110-
assert(dest_addr + dest_offset + dest_size <= memory_region_size(d->vram));
91+
assert(source_addr + source_size <= memory_region_size(d->vram));
92+
assert(dest_addr + dest_size <= memory_region_size(d->vram));
11193

11294
uint8_t *source_row = source + source_offset;
11395
uint8_t *dest_row = dest + dest_offset;
11496

97+
pgraph_vk_download_surfaces_in_range_if_dirty(pg, source_addr, source_size);
98+
99+
// TODO: just clear dirty_draw flag on surfaces that are fully overlapped.
100+
pgraph_vk_download_surfaces_in_range_if_dirty(pg, dest_addr, dest_size);
101+
115102
if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) {
116103
// NV2A_GL_DPRINTF(false, "NV09F_SET_OPERATION_SRCCOPY");
117104
for (unsigned int y = 0; y < image_blit->height; y++) {
@@ -141,8 +128,6 @@ void pgraph_vk_image_blit(NV2AState *d)
141128
assert(false && "Unknown blit operation");
142129
}
143130

144-
NV2A_DPRINTF(" - 0x%tx -> 0x%tx\n", source_addr, dest_addr);
145-
146131
bool needs_alpha_patching;
147132
uint8_t alpha_override;
148133
switch (context_surfaces->color_format) {
@@ -169,9 +154,11 @@ void pgraph_vk_image_blit(NV2AState *d)
169154
}
170155
}
171156

172-
dest_addr += dest_offset;
173157
memory_region_set_client_dirty(d->vram, dest_addr, dest_size,
174158
DIRTY_MEMORY_VGA);
175159
memory_region_set_client_dirty(d->vram, dest_addr, dest_size,
176160
DIRTY_MEMORY_NV2A_TEX);
161+
if (pgraph_vk_mark_surfaces_in_range_for_upload(d, dest_addr, dest_size)) {
162+
++pg->draw_time;
163+
}
177164
}

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)