intel: Map write-only buffer objects through the GTT when possible.
[mesa.git] / src / mesa / drivers / dri / intel / intel_buffer_objects.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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
29 #include "main/imports.h"
30 #include "main/mtypes.h"
31 #include "main/bufferobj.h"
32
33 #include "intel_context.h"
34 #include "intel_buffer_objects.h"
35 #include "intel_batchbuffer.h"
36 #include "intel_regions.h"
37
38 static GLboolean
39 intel_bufferobj_unmap(GLcontext * ctx,
40 GLenum target, struct gl_buffer_object *obj);
41
42 /** Allocates a new dri_bo to store the data for the buffer object. */
43 static void
44 intel_bufferobj_alloc_buffer(struct intel_context *intel,
45 struct intel_buffer_object *intel_obj)
46 {
47 intel_obj->buffer = dri_bo_alloc(intel->bufmgr, "bufferobj",
48 intel_obj->Base.Size, 64);
49 }
50
51 /**
52 * There is some duplication between mesa's bufferobjects and our
53 * bufmgr buffers. Both have an integer handle and a hashtable to
54 * lookup an opaque structure. It would be nice if the handles and
55 * internal structure where somehow shared.
56 */
57 static struct gl_buffer_object *
58 intel_bufferobj_alloc(GLcontext * ctx, GLuint name, GLenum target)
59 {
60 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
61
62 _mesa_initialize_buffer_object(&obj->Base, name, target);
63
64 obj->buffer = NULL;
65
66 return &obj->Base;
67 }
68
69 /* Break the COW tie to the region. The region gets to keep the data.
70 */
71 void
72 intel_bufferobj_release_region(struct intel_context *intel,
73 struct intel_buffer_object *intel_obj)
74 {
75 assert(intel_obj->region->buffer == intel_obj->buffer);
76 intel_obj->region->pbo = NULL;
77 intel_obj->region = NULL;
78
79 dri_bo_unreference(intel_obj->buffer);
80 intel_obj->buffer = NULL;
81 }
82
83 /* Break the COW tie to the region. Both the pbo and the region end
84 * up with a copy of the data.
85 */
86 void
87 intel_bufferobj_cow(struct intel_context *intel,
88 struct intel_buffer_object *intel_obj)
89 {
90 assert(intel_obj->region);
91 intel_region_cow(intel, intel_obj->region);
92 }
93
94
95 /**
96 * Deallocate/free a vertex/pixel buffer object.
97 * Called via glDeleteBuffersARB().
98 */
99 static void
100 intel_bufferobj_free(GLcontext * ctx, struct gl_buffer_object *obj)
101 {
102 struct intel_context *intel = intel_context(ctx);
103 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
104
105 assert(intel_obj);
106
107 /* Buffer objects are automatically unmapped when deleting according
108 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
109 * (though it does if you call glDeleteBuffers)
110 */
111 if (obj->Pointer)
112 intel_bufferobj_unmap(ctx, 0, obj);
113
114 if (intel_obj->region) {
115 intel_bufferobj_release_region(intel, intel_obj);
116 }
117 else if (intel_obj->buffer) {
118 dri_bo_unreference(intel_obj->buffer);
119 }
120
121 _mesa_free(intel_obj);
122 }
123
124
125
126 /**
127 * Allocate space for and store data in a buffer object. Any data that was
128 * previously stored in the buffer object is lost. If data is NULL,
129 * memory will be allocated, but no copy will occur.
130 * Called via glBufferDataARB().
131 */
132 static void
133 intel_bufferobj_data(GLcontext * ctx,
134 GLenum target,
135 GLsizeiptrARB size,
136 const GLvoid * data,
137 GLenum usage, struct gl_buffer_object *obj)
138 {
139 struct intel_context *intel = intel_context(ctx);
140 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
141
142 intel_obj->Base.Size = size;
143 intel_obj->Base.Usage = usage;
144
145 assert(!obj->Pointer); /* Mesa should have unmapped it */
146
147 if (intel_obj->region)
148 intel_bufferobj_release_region(intel, intel_obj);
149
150 if (intel_obj->buffer != NULL) {
151 dri_bo_unreference(intel_obj->buffer);
152 intel_obj->buffer = NULL;
153 }
154 if (size != 0) {
155 intel_bufferobj_alloc_buffer(intel, intel_obj);
156
157 if (data != NULL)
158 dri_bo_subdata(intel_obj->buffer, 0, size, data);
159 }
160 }
161
162
163 /**
164 * Replace data in a subrange of buffer object. If the data range
165 * specified by size + offset extends beyond the end of the buffer or
166 * if data is NULL, no copy is performed.
167 * Called via glBufferSubDataARB().
168 */
169 static void
170 intel_bufferobj_subdata(GLcontext * ctx,
171 GLenum target,
172 GLintptrARB offset,
173 GLsizeiptrARB size,
174 const GLvoid * data, struct gl_buffer_object *obj)
175 {
176 struct intel_context *intel = intel_context(ctx);
177 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
178
179 assert(intel_obj);
180
181 if (intel_obj->region)
182 intel_bufferobj_cow(intel, intel_obj);
183
184 dri_bo_subdata(intel_obj->buffer, offset, size, data);
185 }
186
187
188 /**
189 * Called via glGetBufferSubDataARB().
190 */
191 static void
192 intel_bufferobj_get_subdata(GLcontext * ctx,
193 GLenum target,
194 GLintptrARB offset,
195 GLsizeiptrARB size,
196 GLvoid * data, struct gl_buffer_object *obj)
197 {
198 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
199
200 assert(intel_obj);
201 dri_bo_get_subdata(intel_obj->buffer, offset, size, data);
202 }
203
204
205
206 /**
207 * Called via glMapBufferARB().
208 */
209 static void *
210 intel_bufferobj_map(GLcontext * ctx,
211 GLenum target,
212 GLenum access, struct gl_buffer_object *obj)
213 {
214 struct intel_context *intel = intel_context(ctx);
215 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
216 GLboolean read_only = (access == GL_READ_ONLY_ARB);
217 GLboolean write_only = (access == GL_WRITE_ONLY_ARB);
218
219 assert(intel_obj);
220
221 if (intel_obj->region)
222 intel_bufferobj_cow(intel, intel_obj);
223
224 if (intel_obj->buffer == NULL) {
225 obj->Pointer = NULL;
226 return NULL;
227 }
228
229 if (write_only && intel->intelScreen->kernel_exec_fencing) {
230 drm_intel_gem_bo_map_gtt(intel_obj->buffer);
231 intel_obj->mapped_gtt = GL_TRUE;
232 } else {
233 drm_intel_bo_map(intel_obj->buffer, !read_only);
234 intel_obj->mapped_gtt = GL_FALSE;
235 }
236
237 obj->Pointer = intel_obj->buffer->virtual;
238 return obj->Pointer;
239 }
240
241
242 /**
243 * Called via glMapBufferARB().
244 */
245 static GLboolean
246 intel_bufferobj_unmap(GLcontext * ctx,
247 GLenum target, struct gl_buffer_object *obj)
248 {
249 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
250
251 assert(intel_obj);
252 if (intel_obj->buffer != NULL) {
253 assert(obj->Pointer);
254 if (intel_obj->mapped_gtt) {
255 drm_intel_gem_bo_unmap_gtt(intel_obj->buffer);
256 } else {
257 drm_intel_bo_unmap(intel_obj->buffer);
258 }
259 obj->Pointer = NULL;
260 }
261 return GL_TRUE;
262 }
263
264 dri_bo *
265 intel_bufferobj_buffer(struct intel_context *intel,
266 struct intel_buffer_object *intel_obj, GLuint flag)
267 {
268 if (intel_obj->region) {
269 if (flag == INTEL_WRITE_PART)
270 intel_bufferobj_cow(intel, intel_obj);
271 else if (flag == INTEL_WRITE_FULL) {
272 intel_bufferobj_release_region(intel, intel_obj);
273 intel_bufferobj_alloc_buffer(intel, intel_obj);
274 }
275 }
276
277 return intel_obj->buffer;
278 }
279
280 void
281 intel_bufferobj_init(struct intel_context *intel)
282 {
283 GLcontext *ctx = &intel->ctx;
284
285 ctx->Driver.NewBufferObject = intel_bufferobj_alloc;
286 ctx->Driver.DeleteBuffer = intel_bufferobj_free;
287 ctx->Driver.BufferData = intel_bufferobj_data;
288 ctx->Driver.BufferSubData = intel_bufferobj_subdata;
289 ctx->Driver.GetBufferSubData = intel_bufferobj_get_subdata;
290 ctx->Driver.MapBuffer = intel_bufferobj_map;
291 ctx->Driver.UnmapBuffer = intel_bufferobj_unmap;
292 }