1/************************************************************************** 2 * 3 * Copyright 2006 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/* Provide additional functionality on top of bufmgr buffers: 29 * - 2d semantics and blit operations 30 * - refcounting of buffers for multiple images in a buffer. 31 * - refcounting of buffer mappings. 32 * - some logic for moving the buffers to the best memory pools for 33 * given operations. 34 * 35 * Most of this is to make it easier to implement the fixed-layout 36 * mipmap tree required by intel hardware in the face of GL's 37 * programming interface where each image can be specifed in random 38 * order and it isn't clear what layout the tree should have until the 39 * last moment. 40 */ 41 42#include <sys/ioctl.h> 43#include <errno.h> 44 45#include "main/hash.h" 46#include "intel_context.h" 47#include "intel_regions.h" 48#include "intel_blit.h" 49#include "intel_buffer_objects.h" 50#include "intel_bufmgr.h" 51#include "intel_batchbuffer.h" 52 53#define FILE_DEBUG_FLAG DEBUG_REGION 54 55static struct intel_region * 56intel_region_alloc_internal(struct intel_screen *screen, 57 GLuint cpp, 58 GLuint width, GLuint height, GLuint pitch, 59 uint32_t tiling, drm_intel_bo *buffer) 60{ 61 struct intel_region *region; 62 63 region = calloc(sizeof(*region), 1); 64 if (region == NULL) 65 return region; 66 67 region->cpp = cpp; 68 region->width = width; 69 region->height = height; 70 region->pitch = pitch; 71 region->refcount = 1; 72 region->bo = buffer; 73 region->tiling = tiling; 74 75 DBG("%s <-- %p\n", __func__, region); 76 return region; 77} 78 79struct intel_region * 80intel_region_alloc(struct intel_screen *screen, 81 uint32_t tiling, 82 GLuint cpp, GLuint width, GLuint height, 83 bool expect_accelerated_upload) 84{ 85 drm_intel_bo *buffer; 86 unsigned long flags = 0; 87 unsigned long aligned_pitch; 88 struct intel_region *region; 89 90 if (expect_accelerated_upload) 91 flags |= BO_ALLOC_FOR_RENDER; 92 93 buffer = drm_intel_bo_alloc_tiled(screen->bufmgr, "region", 94 width, height, cpp, 95 &tiling, &aligned_pitch, flags); 96 if (buffer == NULL) 97 return NULL; 98 99 region = intel_region_alloc_internal(screen, cpp, width, height, 100 aligned_pitch, tiling, buffer); 101 if (region == NULL) { 102 drm_intel_bo_unreference(buffer); 103 return NULL; 104 } 105 106 return region; 107} 108 109bool 110intel_region_flink(struct intel_region *region, uint32_t *name) 111{ 112 if (region->name == 0) { 113 if (drm_intel_bo_flink(region->bo, ®ion->name)) 114 return false; 115 } 116 117 *name = region->name; 118 119 return true; 120} 121 122struct intel_region * 123intel_region_alloc_for_handle(struct intel_screen *screen, 124 GLuint cpp, 125 GLuint width, GLuint height, GLuint pitch, 126 GLuint handle, const char *name) 127{ 128 struct intel_region *region; 129 drm_intel_bo *buffer; 130 int ret; 131 uint32_t bit_6_swizzle, tiling; 132 133 buffer = drm_intel_bo_gem_create_from_name(screen->bufmgr, name, handle); 134 if (buffer == NULL) 135 return NULL; 136 ret = drm_intel_bo_get_tiling(buffer, &tiling, &bit_6_swizzle); 137 if (ret != 0) { 138 fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", 139 handle, name, strerror(-ret)); 140 drm_intel_bo_unreference(buffer); 141 return NULL; 142 } 143 144 region = intel_region_alloc_internal(screen, cpp, 145 width, height, pitch, tiling, buffer); 146 if (region == NULL) { 147 drm_intel_bo_unreference(buffer); 148 return NULL; 149 } 150 151 region->name = handle; 152 153 return region; 154} 155 156struct intel_region * 157intel_region_alloc_for_fd(struct intel_screen *screen, 158 GLuint cpp, 159 GLuint width, GLuint height, GLuint pitch, 160 GLuint size, 161 int fd, const char *name) 162{ 163 struct intel_region *region; 164 drm_intel_bo *buffer; 165 int ret; 166 uint32_t bit_6_swizzle, tiling; 167 168 buffer = drm_intel_bo_gem_create_from_prime(screen->bufmgr, fd, size); 169 if (buffer == NULL) 170 return NULL; 171 ret = drm_intel_bo_get_tiling(buffer, &tiling, &bit_6_swizzle); 172 if (ret != 0) { 173 fprintf(stderr, "Couldn't get tiling of buffer (%s): %s\n", 174 name, strerror(-ret)); 175 drm_intel_bo_unreference(buffer); 176 return NULL; 177 } 178 179 region = intel_region_alloc_internal(screen, cpp, 180 width, height, pitch, tiling, buffer); 181 if (region == NULL) { 182 drm_intel_bo_unreference(buffer); 183 return NULL; 184 } 185 186 return region; 187} 188 189void 190intel_region_reference(struct intel_region **dst, struct intel_region *src) 191{ 192 DBG("%s: %p(%d) -> %p(%d)\n", __func__, 193 *dst, *dst ? (*dst)->refcount : 0, src, src ? src->refcount : 0); 194 195 if (src != *dst) { 196 if (*dst) 197 intel_region_release(dst); 198 199 if (src) 200 src->refcount++; 201 *dst = src; 202 } 203} 204 205void 206intel_region_release(struct intel_region **region_handle) 207{ 208 struct intel_region *region = *region_handle; 209 210 if (region == NULL) { 211 DBG("%s NULL\n", __func__); 212 return; 213 } 214 215 DBG("%s %p %d\n", __func__, region, region->refcount - 1); 216 217 assert(region->refcount > 0); 218 region->refcount--; 219 220 if (region->refcount == 0) { 221 drm_intel_bo_unreference(region->bo); 222 223 free(region); 224 } 225 *region_handle = NULL; 226} 227 228/** 229 * This function computes masks that may be used to select the bits of the X 230 * and Y coordinates that indicate the offset within a tile. If the region is 231 * untiled, the masks are set to 0. 232 */ 233void 234intel_region_get_tile_masks(struct intel_region *region, 235 uint32_t *mask_x, uint32_t *mask_y) 236{ 237 int cpp = region->cpp; 238 uint32_t tiling = region->tiling; 239 240 switch (tiling) { 241 default: 242 assert(false); 243 case I915_TILING_NONE: 244 *mask_x = *mask_y = 0; 245 break; 246 case I915_TILING_X: 247 *mask_x = 512 / cpp - 1; 248 *mask_y = 7; 249 break; 250 case I915_TILING_Y: 251 *mask_x = 128 / cpp - 1; 252 *mask_y = 31; 253 break; 254 } 255} 256 257/** 258 * Compute the offset (in bytes) from the start of the region to the given x 259 * and y coordinate. For tiled regions, caller must ensure that x and y are 260 * multiples of the tile size. 261 */ 262uint32_t 263intel_region_get_aligned_offset(struct intel_region *region, uint32_t x, 264 uint32_t y) 265{ 266 int cpp = region->cpp; 267 uint32_t pitch = region->pitch; 268 uint32_t tiling = region->tiling; 269 270 switch (tiling) { 271 default: 272 assert(false); 273 case I915_TILING_NONE: 274 return y * pitch + x * cpp; 275 case I915_TILING_X: 276 assert((x % (512 / cpp)) == 0); 277 assert((y % 8) == 0); 278 return y * pitch + x / (512 / cpp) * 4096; 279 case I915_TILING_Y: 280 assert((x % (128 / cpp)) == 0); 281 assert((y % 32) == 0); 282 return y * pitch + x / (128 / cpp) * 4096; 283 } 284} 285