renderonly.c 4.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * Copyright (C) 2016 Christian Gmeiner <christian.gmeiner@gmail.com>
 *
 * 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:
 *    Christian Gmeiner <christian.gmeiner@gmail.com>
 */

#include "renderonly/renderonly.h"

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <xf86drm.h>

#include "state_tracker/drm_driver.h"
#include "pipe/p_screen.h"
36
#include "util/u_inlines.h"
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
#include "util/u_memory.h"

struct renderonly *
renderonly_dup(const struct renderonly *ro)
{
   struct renderonly *copy;

   copy = CALLOC_STRUCT(renderonly);
   if (!copy)
      return NULL;

   memcpy(copy, ro, sizeof(*ro));

   return copy;
}

struct renderonly_scanout *
renderonly_scanout_for_prime(struct pipe_resource *rsc, struct renderonly *ro)
{
   struct renderonly_scanout *scanout;

   scanout = CALLOC_STRUCT(renderonly_scanout);
   if (!scanout)
      return NULL;

   scanout->prime = rsc;

   return scanout;
}

void
68 69
renderonly_scanout_destroy(struct renderonly_scanout *scanout,
			   struct renderonly *ro)
70
{
71 72 73 74 75
   struct drm_mode_destroy_dumb destroy_dumb = { };

   pipe_resource_reference(&scanout->prime, NULL);
   if (ro->kms_fd != -1) {
      destroy_dumb.handle = scanout->handle;
Philipp Zabel's avatar
Philipp Zabel committed
76
      drmIoctl(ro->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
77
   }
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
   FREE(scanout);
}

struct renderonly_scanout *
renderonly_create_kms_dumb_buffer_for_resource(struct pipe_resource *rsc,
                                               struct renderonly *ro)
{
   struct pipe_screen *screen = rsc->screen;
   struct renderonly_scanout *scanout;
   struct winsys_handle handle;
   int prime_fd, err;
   struct drm_mode_create_dumb create_dumb = {
      .width = rsc->width0,
      .height = rsc->height0,
      .bpp = 32,
   };
   struct drm_mode_destroy_dumb destroy_dumb = { };

   scanout = CALLOC_STRUCT(renderonly_scanout);
   if (!scanout)
      return NULL;

   /* create dumb buffer at scanout GPU */
Philipp Zabel's avatar
Philipp Zabel committed
101
   err = drmIoctl(ro->kms_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
   if (err < 0) {
      fprintf(stderr, "DRM_IOCTL_MODE_CREATE_DUMB failed: %s\n",
            strerror(errno));
      goto free_scanout;
   }

   scanout->handle = create_dumb.handle;
   scanout->stride = create_dumb.pitch;

   /* export dumb buffer */
   err = drmPrimeHandleToFD(ro->kms_fd, create_dumb.handle, O_CLOEXEC,
         &prime_fd);
   if (err < 0) {
      fprintf(stderr, "failed to export dumb buffer: %s\n", strerror(errno));
      goto free_dumb;
   }

   /* import dumb buffer */
   handle.type = DRM_API_HANDLE_TYPE_FD;
   handle.handle = prime_fd;
   handle.stride = create_dumb.pitch;

   scanout->prime = screen->resource_from_handle(screen, rsc,
         &handle, PIPE_HANDLE_USAGE_READ_WRITE);

127 128
   close(prime_fd);

129 130 131 132 133 134 135 136 137
   if (!scanout->prime) {
      fprintf(stderr, "failed to create resource_from_handle: %s\n", strerror(errno));
      goto free_dumb;
   }

   return scanout;

free_dumb:
   destroy_dumb.handle = scanout->handle;
Philipp Zabel's avatar
Philipp Zabel committed
138
   drmIoctl(ro->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

free_scanout:
   FREE(scanout);

   return NULL;
}

struct renderonly_scanout *
renderonly_create_gpu_import_for_resource(struct pipe_resource *rsc,
                                          struct renderonly *ro)
{
   struct pipe_screen *screen = rsc->screen;
   struct renderonly_scanout *scanout;
   boolean status;
   int fd, err;
   struct winsys_handle handle = {
      .type = DRM_API_HANDLE_TYPE_FD
   };

   scanout = CALLOC_STRUCT(renderonly_scanout);
   if (!scanout)
      return NULL;

   status = screen->resource_get_handle(screen, NULL, rsc, &handle,
         PIPE_HANDLE_USAGE_READ_WRITE);
   if (!status)
      goto free_scanout;

   scanout->stride = handle.stride;
   fd = handle.handle;

   err = drmPrimeFDToHandle(ro->kms_fd, fd, &scanout->handle);
   close(fd);

   if (err < 0) {
      fprintf(stderr, "drmPrimeFDToHandle() failed: %s\n", strerror(errno));
      goto free_scanout;
   }

   return scanout;

free_scanout:
   FREE(scanout);

   return NULL;
}