Merge branch 'master' into autoconf2
[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 "imports.h"
30 #include "mtypes.h"
31 #include "bufferobj.h"
32
33 #include "intel_context.h"
34 #include "intel_buffer_objects.h"
35 #include "intel_regions.h"
36 #include "dri_bufmgr.h"
37
38 /** Allocates a new dri_bo to store the data for the buffer object. */
39 static void
40 intel_bufferobj_alloc_buffer(struct intel_context *intel,
41 struct intel_buffer_object *intel_obj)
42 {
43 intel_obj->buffer = dri_bo_alloc(intel->bufmgr, "bufferobj",
44 intel_obj->Base.Size, 64,
45 DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED | DRM_BO_FLAG_CACHED_MAPPED);
46 }
47
48 /**
49 * There is some duplication between mesa's bufferobjects and our
50 * bufmgr buffers. Both have an integer handle and a hashtable to
51 * lookup an opaque structure. It would be nice if the handles and
52 * internal structure where somehow shared.
53 */
54 static struct gl_buffer_object *
55 intel_bufferobj_alloc(GLcontext * ctx, GLuint name, GLenum target)
56 {
57 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
58
59 _mesa_initialize_buffer_object(&obj->Base, name, target);
60
61 obj->buffer = NULL;
62
63 return &obj->Base;
64 }
65
66 /* Break the COW tie to the region. The region gets to keep the data.
67 */
68 void
69 intel_bufferobj_release_region(struct intel_context *intel,
70 struct intel_buffer_object *intel_obj)
71 {
72 assert(intel_obj->region->buffer == intel_obj->buffer);
73 intel_obj->region->pbo = NULL;
74 intel_obj->region = NULL;
75
76 dri_bo_unreference(intel_obj->buffer);
77 intel_obj->buffer = NULL;
78 }
79
80 /* Break the COW tie to the region. Both the pbo and the region end
81 * up with a copy of the data.
82 */
83 void
84 intel_bufferobj_cow(struct intel_context *intel,
85 struct intel_buffer_object *intel_obj)
86 {
87 assert(intel_obj->region);
88 intel_region_cow(intel, intel_obj->region);
89 }
90
91
92 /**
93 * Deallocate/free a vertex/pixel buffer object.
94 * Called via glDeleteBuffersARB().
95 */
96 static void
97 intel_bufferobj_free(GLcontext * ctx, struct gl_buffer_object *obj)
98 {
99 struct intel_context *intel = intel_context(ctx);
100 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
101
102 assert(intel_obj);
103
104 if (intel_obj->region) {
105 intel_bufferobj_release_region(intel, intel_obj);
106 }
107 else if (intel_obj->buffer) {
108 dri_bo_unreference(intel_obj->buffer);
109 }
110
111 _mesa_free(intel_obj);
112 }
113
114
115
116 /**
117 * Allocate space for and store data in a buffer object. Any data that was
118 * previously stored in the buffer object is lost. If data is NULL,
119 * memory will be allocated, but no copy will occur.
120 * Called via glBufferDataARB().
121 */
122 static void
123 intel_bufferobj_data(GLcontext * ctx,
124 GLenum target,
125 GLsizeiptrARB size,
126 const GLvoid * data,
127 GLenum usage, struct gl_buffer_object *obj)
128 {
129 struct intel_context *intel = intel_context(ctx);
130 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
131
132 intel_obj->Base.Size = size;
133 intel_obj->Base.Usage = usage;
134
135 if (intel_obj->region)
136 intel_bufferobj_release_region(intel, intel_obj);
137
138 /* While it would seem to make sense to always reallocate the buffer here,
139 * since it should allow us better concurrency between rendering and
140 * map-cpu write-unmap, doing so was a minor (~10%) performance loss
141 * for both classic and TTM mode with openarena. That may change with
142 * improved buffer manager algorithms.
143 */
144 if (intel_obj->buffer != NULL && intel_obj->buffer->size != size) {
145 dri_bo_unreference(intel_obj->buffer);
146 intel_obj->buffer = NULL;
147 }
148 if (size != 0) {
149 if (intel_obj->buffer == NULL)
150 intel_bufferobj_alloc_buffer(intel, intel_obj);
151
152 if (data != NULL)
153 dri_bo_subdata(intel_obj->buffer, 0, size, data);
154 }
155 }
156
157
158 /**
159 * Replace data in a subrange of buffer object. If the data range
160 * specified by size + offset extends beyond the end of the buffer or
161 * if data is NULL, no copy is performed.
162 * Called via glBufferSubDataARB().
163 */
164 static void
165 intel_bufferobj_subdata(GLcontext * ctx,
166 GLenum target,
167 GLintptrARB offset,
168 GLsizeiptrARB size,
169 const GLvoid * data, struct gl_buffer_object *obj)
170 {
171 struct intel_context *intel = intel_context(ctx);
172 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
173
174 assert(intel_obj);
175
176 if (intel_obj->region)
177 intel_bufferobj_cow(intel, intel_obj);
178
179 dri_bo_subdata(intel_obj->buffer, offset, size, data);
180 }
181
182
183 /**
184 * Called via glGetBufferSubDataARB().
185 */
186 static void
187 intel_bufferobj_get_subdata(GLcontext * ctx,
188 GLenum target,
189 GLintptrARB offset,
190 GLsizeiptrARB size,
191 GLvoid * data, struct gl_buffer_object *obj)
192 {
193 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
194
195 assert(intel_obj);
196 dri_bo_get_subdata(intel_obj->buffer, offset, size, data);
197 }
198
199
200
201 /**
202 * Called via glMapBufferARB().
203 */
204 static void *
205 intel_bufferobj_map(GLcontext * ctx,
206 GLenum target,
207 GLenum access, struct gl_buffer_object *obj)
208 {
209 struct intel_context *intel = intel_context(ctx);
210 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
211
212 /* XXX: Translate access to flags arg below:
213 */
214 assert(intel_obj);
215
216 if (intel_obj->region)
217 intel_bufferobj_cow(intel, intel_obj);
218
219 if (intel_obj->buffer == NULL) {
220 obj->Pointer = NULL;
221 return NULL;
222 }
223
224 dri_bo_map(intel_obj->buffer, GL_TRUE);
225 obj->Pointer = intel_obj->buffer->virtual;
226 return obj->Pointer;
227 }
228
229
230 /**
231 * Called via glMapBufferARB().
232 */
233 static GLboolean
234 intel_bufferobj_unmap(GLcontext * ctx,
235 GLenum target, struct gl_buffer_object *obj)
236 {
237 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
238
239 assert(intel_obj);
240 if (intel_obj->buffer != NULL) {
241 assert(obj->Pointer);
242 dri_bo_unmap(intel_obj->buffer);
243 obj->Pointer = NULL;
244 }
245 return GL_TRUE;
246 }
247
248 dri_bo *
249 intel_bufferobj_buffer(struct intel_context *intel,
250 struct intel_buffer_object *intel_obj, GLuint flag)
251 {
252 if (intel_obj->region) {
253 if (flag == INTEL_WRITE_PART)
254 intel_bufferobj_cow(intel, intel_obj);
255 else if (flag == INTEL_WRITE_FULL) {
256 intel_bufferobj_release_region(intel, intel_obj);
257 intel_bufferobj_alloc_buffer(intel, intel_obj);
258 }
259 }
260
261 return intel_obj->buffer;
262 }
263
264 void
265 intel_bufferobj_init(struct intel_context *intel)
266 {
267 GLcontext *ctx = &intel->ctx;
268
269 ctx->Driver.NewBufferObject = intel_bufferobj_alloc;
270 ctx->Driver.DeleteBuffer = intel_bufferobj_free;
271 ctx->Driver.BufferData = intel_bufferobj_data;
272 ctx->Driver.BufferSubData = intel_bufferobj_subdata;
273 ctx->Driver.GetBufferSubData = intel_bufferobj_get_subdata;
274 ctx->Driver.MapBuffer = intel_bufferobj_map;
275 ctx->Driver.UnmapBuffer = intel_bufferobj_unmap;
276 }