v3dv: implement host-side event handling functions

I am not quite certain that this is the way to go though. Here, we are
expecting that the GPU can set/reset the event inside a command buffer
as a 1x1 pixel clear for example, however, there is still the question
of how we get to implement the command buffer wait on an event, since
reading the docs I haven't found any such functionality to be available.
We could think of implementing this by splitting the command buffer
into multiple jobs at the wait command, and then using a separate
thread for job submissions that would poll the event UBO before sending
it to the kernel, but that looks like a bit of a kludge.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
diff --git a/src/broadcom/vulkan/v3dv_device.c b/src/broadcom/vulkan/v3dv_device.c
index 7ba9ed7..57acb1b 100644
--- a/src/broadcom/vulkan/v3dv_device.c
+++ b/src/broadcom/vulkan/v3dv_device.c
@@ -1821,3 +1821,75 @@
 
    return VK_SUCCESS;
 }
+
+VkResult
+v3dv_CreateEvent(VkDevice _device,
+                 const VkEventCreateInfo *pCreateInfo,
+                 const VkAllocationCallbacks *pAllocator,
+                 VkEvent *pEvent)
+{
+   V3DV_FROM_HANDLE(v3dv_device, device, _device);
+   struct v3dv_event *event =
+      vk_alloc2(&device->alloc, pAllocator, sizeof(*event), 8,
+                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!event)
+      return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   event->bo = v3dv_bo_alloc(device, 4096, "Event BO");
+   if (!event->bo)
+      goto fail_alloc;
+
+   bool ok = v3dv_bo_map(device, event->bo, 4096);
+   if (!ok)
+      goto fail_map;
+
+   /* Events are created in the unsignaled state */
+   *((uint32_t *) event->bo->map) = 0;
+   *pEvent = v3dv_event_to_handle(event);
+
+   return VK_SUCCESS;
+
+fail_map:
+   v3dv_bo_free(device, event->bo);
+fail_alloc:
+   vk_free2(&device->alloc, pAllocator, event);
+   return vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
+}
+
+void
+v3dv_DestroyEvent(VkDevice _device,
+                  VkEvent _event,
+                  const VkAllocationCallbacks *pAllocator)
+{
+   V3DV_FROM_HANDLE(v3dv_device, device, _device);
+   V3DV_FROM_HANDLE(v3dv_event, event, _event);
+
+   if (!event)
+      return;
+
+   v3dv_bo_free(device, event->bo);
+   vk_free2(&device->alloc, pAllocator, event);
+}
+
+VkResult
+v3dv_GetEventStatus(VkDevice _device, VkEvent _event)
+{
+   V3DV_FROM_HANDLE(v3dv_event, event, _event);
+   return *((uint32_t *) event->bo->map) == 1 ? VK_EVENT_SET : VK_EVENT_RESET;
+}
+
+VkResult
+v3dv_SetEvent(VkDevice _device, VkEvent _event)
+{
+   V3DV_FROM_HANDLE(v3dv_event, event, _event);
+   *((uint32_t *) event->bo->map) = 1;
+   return VK_SUCCESS;
+}
+
+VkResult
+v3dv_ResetEvent(VkDevice _device, VkEvent _event)
+{
+   V3DV_FROM_HANDLE(v3dv_event, event, _event);
+   *((uint32_t *) event->bo->map) = 0;
+   return VK_SUCCESS;
+}
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 1eb6de4..943c4e0 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -655,6 +655,10 @@
    int32_t fd;
 };
 
+struct v3dv_event {
+   struct v3dv_bo *bo;
+};
+
 struct v3dv_shader_module {
    unsigned char sha1[20];
    uint32_t size;
@@ -1019,6 +1023,7 @@
 V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_descriptor_pool, VkDescriptorPool)
 V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_descriptor_set, VkDescriptorSet)
 V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_descriptor_set_layout, VkDescriptorSetLayout)
+V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_event, VkEvent)
 V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_fence, VkFence)
 V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_framebuffer, VkFramebuffer)
 V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_image, VkImage)