[PATCH 3/3] wined3d: Handle NOOVERWRITE maps on persistently mapped Vulkan buffers from the client thread.
Zebediah Figura
zfigura at codeweavers.com
Sun Oct 10 22:53:23 CDT 2021
On 10/8/21 11:24 AM, Henri Verbeet wrote:
> On Thu, 7 Oct 2021 at 04:22, Zebediah Figura <zfigura at codeweavers.com> wrote:
>> +static void adapter_vk_flush_bo_address(struct wined3d_context *context,
>> + const struct wined3d_const_bo_address *data, size_t size)
>> +{
>> + struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
>> + const struct wined3d_vk_info *vk_info;
>> + struct wined3d_device_vk *device_vk;
>> + VkMappedMemoryRange range;
>> + struct wined3d_bo_vk *bo;
>> +
>> + if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
>> + return;
>> +
>> + vk_info = context_vk->vk_info;
>> + device_vk = wined3d_device_vk(context->device);
>> +
>> + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
>> + range.pNext = NULL;
>> + range.memory = bo->vk_memory;
>> + range.offset = bo->memory_offset + (uintptr_t)data->addr;
>> + range.size = size;
>> + VK_CALL(vkFlushMappedMemoryRanges(device_vk->vk_device, 1, &range));
>> +}
>> +
> That has a fair amount of overlap with adapter_vk_unmap_bo_address().
> Would a common helper make sense?
Indeed, although the common helper may end up just being
adapter_vk_flush_bo_address()...
>
>> +static void *adapter_vk_alloc_upload_bo(struct wined3d_device *device, struct wined3d_resource *resource,
>> + unsigned int sub_resource_idx, const struct wined3d_box *box, unsigned int *row_pitch,
>> + unsigned int *slice_pitch, uint32_t flags, struct upload_bo *upload_bo)
>> +{
>> + wined3d_not_from_cs(device->cs);
>> +
>> + /* Limit NOOVERWRITE maps to buffers for now; there are too many ways that
>> + * a texture can be invalidated to even count. */
>> + if (wined3d_map_persistent() && resource->type == WINED3D_RTYPE_BUFFER && (flags & WINED3D_MAP_NOOVERWRITE))
>> + {
>> + struct wined3d_client_sub_resource *sub_resource;
>> + const struct wined3d_bo_vk *bo_vk;
>> + uint8_t *map_ptr;
>> +
>> + sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
>> +
>> + bo_vk = (const struct wined3d_bo_vk *)sub_resource->addr.buffer_object;
>> + map_ptr = bo_vk ? bo_vk->map_ptr : NULL;
>> + map_ptr += (uintptr_t)sub_resource->addr.addr;
>> +
>> + if (!map_ptr)
>> + {
>> + TRACE("Sub-resource is not persistently mapped.\n");
>> + return NULL;
>> + }
>> +
>> + wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx, row_pitch, slice_pitch);
>> +
>> + upload_bo->addr = *wined3d_const_bo_address(&sub_resource->addr);
>> + upload_bo->flags = 0;
>> + if (bo_vk)
>> + map_ptr += bo_vk->memory_offset;
>> + map_ptr = resource_offset_map_pointer(resource, sub_resource_idx, map_ptr, box);
>> +
>> + if (!(bo_vk->memory_type & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
>> + upload_bo->flags |= UPLOAD_BO_FLUSH_ON_UNMAP;
>> +
>> + return map_ptr;
>> + }
>> +
>> + return NULL;
>> +}
>
> Do we need adapter_vk_alloc_upload_bo() as such? I suppose it would
> make sense to expose something like wined3d_context_vk_create_bo()
> through the adapter ops, but the "upload bo" mechanism seems more
> generic than that. In its current form, this also doesn't allocate all
> that much, and doesn't seem that all that specific to the Vulkan
> backend. We use the wined3d_bo_vk structure, but the "map_ptr" and
> "memory_offset" would apply just as well to a GL equivalent. I.e., if
> we introduced a common wined3d_bo structure, this could just be in
> wined3d_cs_map_upload_bo().
We don't need it yet, in this patch. We will need it later (or at least,
it looks harder to make accelerated discard generic), but I believe we
should be able to pull out the NOOVERWRITE parts, and, as you say, make
a function called "alloc" really always allocate something.
>
>> +static void invalidate_persistent_map(struct wined3d_resource *resource, unsigned int sub_resource_idx)
>> +{
>> + struct wined3d_client_sub_resource *sub_resource;
>> +
>> + sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
>> + memset(&sub_resource->addr, 0, sizeof(sub_resource->addr));
>> +}
>> +
> Is this function correctly named? It doesn't quite do what I'd expect
> something called invalidate_persistent_map() to do.
>
I suppose your expectation is that it invalidates the map contents,
which it does not, but rather it invalidates the map pointer. I don't
know how better to name it to clarify that difference. (Shove a _ptr
onto the end, maybe?)
Essentially it means "the CS thread might reallocate the BO behind our
back, thereby invalidating bo->map_ptr, which means we can't treat this
one as canonical anymore". It's definitely awkward, but I don't see a
better way to achieve this...
>> @@ -2511,6 +2539,9 @@ HRESULT wined3d_device_context_emit_map(struct wined3d_device_context *context,
>>
>> wined3d_resource_wait_idle(resource);
>>
>> + /* We might end up loading the resource into sysmem. */
>> + invalidate_persistent_map(resource, sub_resource_idx);
>> +
> Sure, we might end up loading the resource into sysmem. That doesn't
> necessarily explain why we would need to call
> invalidate_persistent_map() though. (I.e., the issue is with
> invalidating the BUFFER location, not so much with loading into the
> SYSMEM location.)
>
Right, I'll try to clarify that comment.
>> @@ -2554,7 +2585,7 @@ HRESULT wined3d_device_context_emit_unmap(struct wined3d_device_context *context
>> unsigned int row_pitch, slice_pitch;
>>
>> wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx, &row_pitch, &slice_pitch);
>> - if (bo.flags & UPLOAD_BO_UPLOAD_ON_UNMAP)
>> + if (bo.flags & (UPLOAD_BO_UPLOAD_ON_UNMAP | UPLOAD_BO_FLUSH_ON_UNMAP))
>> wined3d_device_context_upload_bo(context, resource, sub_resource_idx, &box, &bo, row_pitch, slice_pitch);
>> return WINED3D_OK;
>> }
> Uploading when FLUSH_ON_UNMAP is set seems odd. I.e., should there
> ever be a case where FLUSH_ON_UNMAP is set, UPLOAD_ON_UNMAP is not
> set, and we still want to call wined3d_device_context_upload_bo()?
>
As it stands this patch never has both FLUSH_ON_UNMAP and
UPLOAD_ON_UNMAP set at the same time. I essentially was thinking of them
as different things to do on an unmap. I guess in that sense "UPLOAD"
should really have been "COPY" or "BLIT" or something.
>> @@ -2581,8 +2612,7 @@ static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *
>> if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
>> {
>> wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
>> - buffer_from_resource(op->src_resource), op->src_box.left,
>> - op->src_box.right - op->src_box.left);
>> + buffer_from_resource(op->src_resource), op->src_box.left, op->src_box.right - op->src_box.left);
>> }
> That's a whitespace change. The change is not particularly wrong, but
> it doesn't seem particularly relevant to the rest of this patch
> either.
Oops, must have been left over from something else...
>
>> + /* This might result in an implicit discard. */
>> + if (dst_resource->type == WINED3D_RTYPE_BUFFER && dst_box->right - dst_box->left == dst_resource->size)
>> + invalidate_persistent_map(dst_resource, 0);
>> +
> Somewhat like the other invalidate_persistent_map() comment above, it
> would require someone to already be fairly familiar with the code in
> question to understand the comment. (I.e., the issue here is that if
> the CS thread does end up doing a DISCARD for this operation, any
> subsequent operations would need to reference the new bo instead of
> the current one.)
>
>> @@ -2727,8 +2761,22 @@ static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const voi
>> if (resource->type == WINED3D_RTYPE_BUFFER)
>> {
>> struct wined3d_buffer *buffer = buffer_from_resource(resource);
>> + size_t size = box->right - box->left;
>>
>> - wined3d_buffer_copy_bo_address(buffer, context, box->left, &op->bo.addr, box->right - box->left);
>> + if (op->bo.flags & UPLOAD_BO_FLUSH_ON_UNMAP)
>> + {
>> + wined3d_context_flush_bo_address(context, &op->bo.addr, size);
>> + }
>> + else
>> + {
>> + wined3d_buffer_copy_bo_address(buffer, context, box->left, &op->bo.addr, size);
>> + }
>> + goto done;
>> + }
>> +
> It seems like we're mostly using FLUSH_ON_UNMAP here to determine
> whether "op->bo.addr" refers to the same GPU memory as
> "buffer->buffer_object". Could we perhaps just compare them?
I think that works.
>
>> static bool wined3d_cs_unmap_upload_bo(struct wined3d_device_context *context, struct wined3d_resource *resource,
>> unsigned int sub_resource_idx, struct wined3d_box *box, struct upload_bo *bo)
>> {
>> + struct wined3d_client_sub_resource *sub_resource;
>> +
>> + sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
>> + if (sub_resource->upload_bo.addr.buffer_object || sub_resource->upload_bo.addr.addr)
>> + {
> I guess that works; could perhaps do with a helper.
Sure.
>
>> + *bo = sub_resource->upload_bo;
>> + *box = sub_resource->upload_box;
>> + memset(&sub_resource->upload_bo, 0, sizeof(sub_resource->upload_bo));
>> + memset(&sub_resource->upload_box, 0, sizeof(sub_resource->upload_box));
>> + return true;
>> + }
>> +
>> return false;
>> }
>>
> We might as well just return if the condition is false, and save some
> indentation.
>
>> +struct wined3d_client_sub_resource
>> +{
>> + struct wined3d_bo_address addr;
>> +
>> + struct upload_bo upload_bo;
>> + struct wined3d_box upload_box;
>> +};
>> +
> I'm tempted to think we want to track this per resource instead of per
> sub-resource. For buffers it doesn't really matter though, and for
> textures we don't implement it yet. Perhaps we should just leave
> textures alone for now? That would also avoid
> wined3d_resource_get_client_sub_resource() for the moment.
>
Indeed.
Although I've found already that some games could really do with
accelerated texture discard :-/
More information about the wine-devel
mailing list