blob: 9ecf2dcbbbaaf858d6ba1826e0e3217741f06236 [file] [log] [blame]
// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "WaylandSurfaceKHR.hpp"
#include "libWaylandClient.hpp"
#include "Vulkan/VkDeviceMemory.hpp"
#include "Vulkan/VkImage.hpp"
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
namespace vk {
bool WaylandSurfaceKHR::isSupported()
{
return libWaylandClient.isPresent();
}
static void wl_registry_handle_global(void *data, struct wl_registry *registry, unsigned int name, const char *interface, unsigned int version)
{
struct wl_shm **pshm = (struct wl_shm **)data;
if(!strcmp(interface, "wl_shm"))
{
*pshm = static_cast<struct wl_shm *>(libWaylandClient->wl_registry_bind(registry, name, libWaylandClient->wl_shm_interface, 1));
}
}
static void wl_registry_handle_global_remove(void *data, struct wl_registry *registry, unsigned int name)
{
}
static const struct wl_registry_listener wl_registry_listener = { wl_registry_handle_global, wl_registry_handle_global_remove };
WaylandSurfaceKHR::WaylandSurfaceKHR(const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, void *mem)
: display(pCreateInfo->display)
, surface(pCreateInfo->surface)
{
struct wl_registry *registry = libWaylandClient->wl_display_get_registry(display);
libWaylandClient->wl_registry_add_listener(registry, &wl_registry_listener, &shm);
libWaylandClient->wl_display_dispatch(display);
}
void WaylandSurfaceKHR::destroySurface(const VkAllocationCallbacks *pAllocator)
{
}
size_t WaylandSurfaceKHR::ComputeRequiredAllocationSize(const VkWaylandSurfaceCreateInfoKHR *pCreateInfo)
{
return 0;
}
VkResult WaylandSurfaceKHR::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
{
setCommonSurfaceCapabilities(pSurfaceCapabilities);
pSurfaceCapabilities->currentExtent = { 0xFFFFFFFF, 0xFFFFFFFF };
pSurfaceCapabilities->minImageExtent = { 1, 1 };
pSurfaceCapabilities->maxImageExtent = { 0xFFFFFFFF, 0xFFFFFFFF };
return VK_SUCCESS;
}
void WaylandSurfaceKHR::attachImage(PresentImage *image)
{
WaylandImage *wlImage = new WaylandImage;
char path[] = "/tmp/XXXXXX";
int fd = mkstemp(path);
const VkExtent3D &extent = image->getImage()->getExtent();
int stride = image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
assert(ftruncate(fd, extent.height * stride) == 0);
struct wl_shm_pool *pool = libWaylandClient->wl_shm_create_pool(shm, fd, extent.height * stride);
wlImage->buffer = libWaylandClient->wl_shm_pool_create_buffer(pool, 0, extent.width, extent.height, stride, WL_SHM_FORMAT_XRGB8888);
wlImage->data = static_cast<uint8_t *>(mmap(NULL, extent.height * stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
libWaylandClient->wl_shm_pool_destroy(pool);
close(fd);
imageMap[image] = wlImage;
}
void WaylandSurfaceKHR::detachImage(PresentImage *image)
{
auto it = imageMap.find(image);
if(it != imageMap.end())
{
WaylandImage *wlImage = it->second;
const VkExtent3D &extent = image->getImage()->getExtent();
int stride = image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
munmap(wlImage->data, extent.height * stride);
libWaylandClient->wl_buffer_destroy(wlImage->buffer);
delete wlImage;
imageMap.erase(it);
}
}
VkResult WaylandSurfaceKHR::present(PresentImage *image)
{
auto it = imageMap.find(image);
if(it != imageMap.end())
{
WaylandImage *wlImage = it->second;
const VkExtent3D &extent = image->getImage()->getExtent();
int bufferRowPitch = image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
image->getImage()->copyTo(reinterpret_cast<uint8_t *>(wlImage->data), bufferRowPitch);
libWaylandClient->wl_surface_attach(surface, wlImage->buffer, 0, 0);
libWaylandClient->wl_surface_damage(surface, 0, 0, extent.width, extent.height);
libWaylandClient->wl_surface_commit(surface);
libWaylandClient->wl_display_roundtrip(display);
libWaylandClient->wl_display_sync(display);
}
return VK_SUCCESS;
}
} // namespace vk