/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Benjamin Franzke <benjaminfranzke@googlemail.com>
*/
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "state_tracker/drm_driver.h"
#include <unistd.h>
#include <sys/types.h>
#include "gbm_gallium_drmint.h"
/* For importing wl_buffer */
#if HAVE_WAYLAND_PLATFORM
#include "../../../egl/wayland/wayland-drm/wayland-drm.h"
#endif
static INLINE enum pipe_format
gbm_format_to_gallium(enum gbm_bo_format format)
{
switch (format) {
case GBM_BO_FORMAT_XRGB8888:
return PIPE_FORMAT_B8G8R8X8_UNORM;
case GBM_BO_FORMAT_ARGB8888:
return PIPE_FORMAT_B8G8R8A8_UNORM;
default:
return PIPE_FORMAT_NONE;
}
return PIPE_FORMAT_NONE;
}
static INLINE uint
gbm_usage_to_gallium(uint usage)
{
uint resource_usage = 0;
if (usage & GBM_BO_USE_SCANOUT)
resource_usage |= PIPE_BIND_SCANOUT;
if (usage & GBM_BO_USE_RENDERING)
resource_usage |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
if (usage & GBM_BO_USE_CURSOR_64X64)
resource_usage |= PIPE_BIND_CURSOR;
return resource_usage;
}
static int
gbm_gallium_drm_is_format_supported(struct gbm_device *gbm,
enum gbm_bo_format format,
uint32_t usage)
{
struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
enum pipe_format pf;
pf = gbm_format_to_gallium(format);
if (pf == PIPE_FORMAT_NONE)
return 0;
if (!gdrm->screen->is_format_supported(gdrm->screen, PIPE_TEXTURE_2D, pf, 0,
gbm_usage_to_gallium(usage)))
return 0;
if (usage & GBM_BO_USE_SCANOUT && format != GBM_BO_FORMAT_XRGB8888)
return 0;
return 1;
}
static void
gbm_gallium_drm_bo_destroy(struct gbm_bo *_bo)
{
struct gbm_gallium_drm_bo *bo = gbm_gallium_drm_bo(_bo);
pipe_resource_reference(&bo->resource, NULL);
free(bo);
}
static struct gbm_bo *
gbm_gallium_drm_bo_import(struct gbm_device *gbm,
uint32_t type, void *buffer, uint32_t usage)
{
struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
struct gbm_gallium_drm_bo *bo;
struct winsys_handle whandle;
struct pipe_resource *resource;
switch (type) {
#if HAVE_WAYLAND_PLATFORM
case GBM_BO_IMPORT_WL_BUFFER:
{
struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
resource = wb->driver_buffer;
break;
}
#endif
case GBM_BO_IMPORT_EGL_IMAGE:
if (!gdrm->lookup_egl_image)
return NULL;
resource = gdrm->lookup_egl_image(gdrm->lookup_egl_image_data, buffer);
if (resource == NULL)
return NULL;
break;
default:
return NULL;
}
bo = CALLOC_STRUCT(gbm_gallium_drm_bo);
if (bo == NULL)
return NULL;
bo->base.base.gbm = gbm;
bo->base.base.width = resource->width0;
bo->base.base.height = resource->height0;
switch (resource->format) {
case PIPE_FORMAT_B8G8R8X8_UNORM:
bo->base.base.format = GBM_BO_FORMAT_XRGB8888;
break;
case PIPE_FORMAT_B8G8R8A8_UNORM:
bo->base.base.format = GBM_BO_FORMAT_ARGB8888;
break;
default:
FREE(bo);
return NULL;
}
pipe_resource_reference(&bo->resource, resource);
memset(&whandle, 0, sizeof(whandle));
whandle.type = DRM_API_HANDLE_TYPE_KMS;
gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle);
bo->base.base.handle.u32 = whandle.handle;
bo->base.base.stride = whandle.stride;
return &bo->base.base;
}
static struct gbm_bo *
gbm_gallium_drm_bo_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
enum gbm_bo_format format, uint32_t usage)
{
struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
struct gbm_gallium_drm_bo *bo;
struct pipe_resource templ;
struct winsys_handle whandle;
enum pipe_format pf;
bo = CALLOC_STRUCT(gbm_gallium_drm_bo);
if (bo == NULL)
return NULL;
bo->base.base.gbm = gbm;
bo->base.base.width = width;
bo->base.base.height = height;
bo->base.base.format = format;
pf = gbm_format_to_gallium(format);
if (pf == PIPE_FORMAT_NONE)
return NULL;
memset(&templ, 0, sizeof(templ));
templ.bind = gbm_usage_to_gallium(usage);
templ.format = pf;
templ.target = PIPE_TEXTURE_2D;
templ.last_level = 0;
templ.width0 = width;
templ.height0 = height;
templ.depth0 = 1;
templ.array_size = 1;
bo->resource = gdrm->screen->resource_create(gdrm->screen, &templ);
if (bo->resource == NULL) {
FREE(bo);
return NULL;
}
memset(&whandle, 0, sizeof(whandle));
whandle.type = DRM_API_HANDLE_TYPE_KMS;
gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle);
bo->base.base.handle.u32 = whandle.handle;
bo->base.base.stride = whandle.stride;
return &bo->base.base;
}
static void
gbm_gallium_drm_destroy(struct gbm_device *gbm)
{
struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
gallium_screen_destroy(gdrm);
FREE(gdrm);
}
struct gbm_device *
gbm_gallium_drm_device_create(int fd)
{
struct gbm_gallium_drm_device *gdrm;
int ret;
gdrm = calloc(1, sizeof *gdrm);
gdrm->base.base.fd = fd;
gdrm->base.base.bo_create = gbm_gallium_drm_bo_create;
gdrm->base.base.bo_import = gbm_gallium_drm_bo_import;
gdrm->base.base.bo_destroy = gbm_gallium_drm_bo_destroy;
gdrm->base.base.is_format_supported = gbm_gallium_drm_is_format_supported;
gdrm->base.base.destroy = gbm_gallium_drm_destroy;
gdrm->base.type = GBM_DRM_DRIVER_TYPE_GALLIUM;
gdrm->base.base.name = "drm";
ret = gallium_screen_create(gdrm);
if (ret) {
free(gdrm);
return NULL;
}
return &gdrm->base.base;
}