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 
55 static struct intel_region *
intel_region_alloc_internal(struct intel_screen * screen,GLuint cpp,GLuint width,GLuint height,GLuint pitch,uint32_t tiling,drm_intel_bo * buffer)56 intel_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 
79 struct intel_region *
intel_region_alloc(struct intel_screen * screen,uint32_t tiling,GLuint cpp,GLuint width,GLuint height,bool expect_accelerated_upload)80 intel_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 
109 bool
intel_region_flink(struct intel_region * region,uint32_t * name)110 intel_region_flink(struct intel_region *region, uint32_t *name)
111 {
112    if (region->name == 0) {
113       if (drm_intel_bo_flink(region->bo, &region->name))
114 	 return false;
115    }
116 
117    *name = region->name;
118 
119    return true;
120 }
121 
122 struct intel_region *
intel_region_alloc_for_handle(struct intel_screen * screen,GLuint cpp,GLuint width,GLuint height,GLuint pitch,GLuint handle,const char * name)123 intel_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 
156 struct intel_region *
intel_region_alloc_for_fd(struct intel_screen * screen,GLuint cpp,GLuint width,GLuint height,GLuint pitch,GLuint size,int fd,const char * name)157 intel_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 
189 void
intel_region_reference(struct intel_region ** dst,struct intel_region * src)190 intel_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 
205 void
intel_region_release(struct intel_region ** region_handle)206 intel_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  */
233 void
intel_region_get_tile_masks(struct intel_region * region,uint32_t * mask_x,uint32_t * mask_y)234 intel_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  */
262 uint32_t
intel_region_get_aligned_offset(struct intel_region * region,uint32_t x,uint32_t y)263 intel_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