OSDN Git Service

meta: Add an implementation of GetTexSubImage for PBOs
[android-x86/external-mesa.git] / src / mesa / drivers / common / meta_tex_subimage.c
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2015 Intel Corporation.  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 "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Jason Ekstrand <jason.ekstrand@intel.com>
26  */
27
28 #include "bufferobj.h"
29 #include "buffers.h"
30 #include "fbobject.h"
31 #include "glformats.h"
32 #include "glheader.h"
33 #include "image.h"
34 #include "macros.h"
35 #include "meta.h"
36 #include "pbo.h"
37 #include "shaderapi.h"
38 #include "state.h"
39 #include "teximage.h"
40 #include "texobj.h"
41 #include "texstate.h"
42 #include "uniforms.h"
43 #include "varray.h"
44
45 static struct gl_texture_image *
46 create_texture_for_pbo(struct gl_context *ctx, bool create_pbo,
47                        GLenum pbo_target, int width, int height, int depth,
48                        GLenum format, GLenum type, const void *pixels,
49                        const struct gl_pixelstore_attrib *packing,
50                        GLuint *tmp_pbo, GLuint *tmp_tex)
51 {
52    uint32_t pbo_format;
53    GLenum internal_format;
54    unsigned row_stride;
55    struct gl_buffer_object *buffer_obj;
56    struct gl_texture_object *tex_obj;
57    struct gl_texture_image *tex_image;
58    bool read_only;
59
60    if ((packing->ImageHeight != 0 && packing->ImageHeight != height) ||
61        packing->SwapBytes ||
62        packing->LsbFirst ||
63        packing->Invert)
64       return NULL;
65
66    pbo_format = _mesa_format_from_format_and_type(format, type);
67    if (_mesa_format_is_mesa_array_format(pbo_format))
68       pbo_format = _mesa_format_from_array_format(pbo_format);
69
70    if (!pbo_format || !ctx->TextureFormatSupported[pbo_format])
71       return NULL;
72
73    /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */
74    pixels = _mesa_image_address3d(packing, pixels,
75                                   width, height, format, type, 0, 0, 0);
76    row_stride = _mesa_image_row_stride(packing, width, format, type);
77
78    if (_mesa_is_bufferobj(packing->BufferObj)) {
79       *tmp_pbo = 0;
80       buffer_obj = packing->BufferObj;
81    } else {
82       assert(create_pbo);
83
84       _mesa_GenBuffers(1, tmp_pbo);
85
86       /* We are not doing this inside meta_begin/end.  However, we know the
87        * client doesn't have the given target bound, so we can go ahead and
88        * squash it.  We'll set it back when we're done.
89        */
90       _mesa_BindBuffer(pbo_target, *tmp_pbo);
91
92       _mesa_BufferData(pbo_target, row_stride * height, pixels, GL_STREAM_DRAW);
93
94       buffer_obj = ctx->Unpack.BufferObj;
95       pixels = NULL;
96
97       _mesa_BindBuffer(pbo_target, 0);
98    }
99
100    _mesa_GenTextures(1, tmp_tex);
101    tex_obj = _mesa_lookup_texture(ctx, *tmp_tex);
102    tex_obj->Target = depth > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
103    tex_obj->Immutable = GL_TRUE;
104    _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D);
105
106    internal_format = _mesa_get_format_base_format(pbo_format);
107
108    tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0);
109    _mesa_init_teximage_fields(ctx, tex_image, width, height, depth,
110                               0, internal_format, pbo_format);
111
112    read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER;
113    if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj,
114                                                      buffer_obj,
115                                                      (intptr_t)pixels,
116                                                      row_stride,
117                                                      read_only)) {
118       _mesa_DeleteTextures(1, tmp_tex);
119       _mesa_DeleteBuffers(1, tmp_pbo);
120       return NULL;
121    }
122
123    return tex_image;
124 }
125
126 bool
127 _mesa_meta_pbo_TexSubImage(struct gl_context *ctx, GLuint dims,
128                            struct gl_texture_image *tex_image,
129                            int xoffset, int yoffset, int zoffset,
130                            int width, int height, int depth,
131                            GLenum format, GLenum type, const void *pixels,
132                            bool allocate_storage, bool create_pbo,
133                            const struct gl_pixelstore_attrib *packing)
134 {
135    GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 };
136    struct gl_texture_image *pbo_tex_image;
137    GLenum status;
138    bool success = false;
139
140    /* XXX: This should probably be passed in from somewhere */
141    const char *where = "_mesa_meta_pbo_TexSubImage";
142
143    if (!_mesa_is_bufferobj(packing->BufferObj) && !create_pbo)
144       return false;
145
146    if (format == GL_DEPTH_COMPONENT ||
147        format == GL_DEPTH_STENCIL ||
148        format == GL_STENCIL_INDEX ||
149        format == GL_COLOR_INDEX)
150       return false;
151
152    if (ctx->_ImageTransferState)
153       return false;
154
155    if (!_mesa_validate_pbo_access(dims, packing, width, height, depth,
156                                   format, type, INT_MAX, pixels)) {
157       _mesa_error(ctx, GL_INVALID_OPERATION,
158                   "%s(out of bounds PBO access)", where);
159       return true;
160    }
161
162    if (_mesa_check_disallowed_mapping(packing->BufferObj)) {
163       /* buffer is mapped - that's an error */
164       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
165       return true;
166    }
167
168    pbo_tex_image = create_texture_for_pbo(ctx, create_pbo,
169                                           GL_PIXEL_UNPACK_BUFFER,
170                                           width, height, depth,
171                                           format, type, pixels, packing,
172                                           &pbo, &pbo_tex);
173    if (!pbo_tex_image)
174       return false;
175
176    if (allocate_storage)
177       ctx->Driver.AllocTextureImageBuffer(ctx, tex_image);
178
179    /* Only stash the current FBO */
180    _mesa_meta_begin(ctx, 0);
181
182    _mesa_GenFramebuffers(2, fbos);
183    _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
184    _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
185
186    if (tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
187       assert(depth == 1);
188       depth = height;
189       height = 1;
190    }
191
192    _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
193                              pbo_tex_image, 0);
194    /* If this passes on the first layer it should pass on the others */
195    status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
196    if (status != GL_FRAMEBUFFER_COMPLETE)
197       goto fail;
198
199    _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
200                              tex_image, zoffset);
201    /* If this passes on the first layer it should pass on the others */
202    status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
203    if (status != GL_FRAMEBUFFER_COMPLETE)
204       goto fail;
205
206    _mesa_update_state(ctx);
207
208    if (_mesa_meta_BlitFramebuffer(ctx, 0, 0, width, height,
209                                   xoffset, yoffset,
210                                   xoffset + width, yoffset + height,
211                                   GL_COLOR_BUFFER_BIT, GL_NEAREST))
212       goto fail;
213
214    for (int z = 1; z < depth; z++) {
215       _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
216                                 pbo_tex_image, z);
217       _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
218                                 tex_image, zoffset + z);
219
220       _mesa_update_state(ctx);
221
222       _mesa_meta_BlitFramebuffer(ctx, 0, 0, width, height,
223                                  xoffset, yoffset,
224                                  xoffset + width, yoffset + height,
225                                  GL_COLOR_BUFFER_BIT, GL_NEAREST);
226    }
227
228    success = true;
229
230 fail:
231    _mesa_DeleteFramebuffers(2, fbos);
232    _mesa_DeleteTextures(1, &pbo_tex);
233    _mesa_DeleteBuffers(1, &pbo);
234
235    _mesa_meta_end(ctx);
236
237    return success;
238 }
239
240 bool
241 _mesa_meta_pbo_GetTexSubImage(struct gl_context *ctx, GLuint dims,
242                               struct gl_texture_image *tex_image,
243                               int xoffset, int yoffset, int zoffset,
244                               int width, int height, int depth,
245                               GLenum format, GLenum type, const void *pixels,
246                               const struct gl_pixelstore_attrib *packing)
247 {
248    GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 };
249    struct gl_texture_image *pbo_tex_image;
250    GLenum status;
251    bool success = false;
252
253    /* XXX: This should probably be passed in from somewhere */
254    const char *where = "_mesa_meta_pbo_GetTexSubImage";
255
256    if (!_mesa_is_bufferobj(packing->BufferObj))
257       return false;
258
259    if (format == GL_DEPTH_COMPONENT ||
260        format == GL_DEPTH_STENCIL ||
261        format == GL_STENCIL_INDEX ||
262        format == GL_COLOR_INDEX)
263       return false;
264
265    if (ctx->_ImageTransferState)
266       return false;
267
268    if (!_mesa_validate_pbo_access(dims, packing, width, height, depth,
269                                   format, type, INT_MAX, pixels)) {
270       _mesa_error(ctx, GL_INVALID_OPERATION,
271                   "%s(out of bounds PBO access)", where);
272       return true;
273    }
274
275    if (_mesa_check_disallowed_mapping(packing->BufferObj)) {
276       /* buffer is mapped - that's an error */
277       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
278       return true;
279    }
280
281    pbo_tex_image = create_texture_for_pbo(ctx, false, GL_PIXEL_PACK_BUFFER,
282                                           width, height, depth,
283                                           format, type, pixels, packing,
284                                           &pbo, &pbo_tex);
285    if (!pbo_tex_image)
286       return false;
287
288    /* Only stash the current FBO */
289    _mesa_meta_begin(ctx, 0);
290
291    _mesa_GenFramebuffers(2, fbos);
292
293    if (tex_image && tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
294       assert(depth == 1);
295       depth = height;
296       height = 1;
297    }
298
299    /* If we were given a texture, bind it to the read framebuffer.  If not,
300     * we're doing a ReadPixels and we should just use whatever framebuffer
301     * the client has bound.
302     */
303    if (tex_image) {
304       _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
305       _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
306                                 tex_image, zoffset);
307       /* If this passes on the first layer it should pass on the others */
308       status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
309       if (status != GL_FRAMEBUFFER_COMPLETE)
310          goto fail;
311    } else {
312       assert(depth == 1);
313    }
314
315    _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
316    _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
317                              pbo_tex_image, 0);
318    /* If this passes on the first layer it should pass on the others */
319    status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
320    if (status != GL_FRAMEBUFFER_COMPLETE)
321       goto fail;
322
323    _mesa_update_state(ctx);
324
325    if (_mesa_meta_BlitFramebuffer(ctx, xoffset, yoffset,
326                                   xoffset + width, yoffset + height,
327                                   0, 0, width, height,
328                                   GL_COLOR_BUFFER_BIT, GL_NEAREST))
329       goto fail;
330
331    for (int z = 1; z < depth; z++) {
332       _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
333                                 tex_image, zoffset + z);
334       _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
335                                 pbo_tex_image, z);
336
337       _mesa_update_state(ctx);
338
339       _mesa_meta_BlitFramebuffer(ctx, xoffset, yoffset,
340                                  xoffset + width, yoffset + height,
341                                  0, 0, width, height,
342                                  GL_COLOR_BUFFER_BIT, GL_NEAREST);
343    }
344
345    success = true;
346
347 fail:
348    _mesa_DeleteFramebuffers(2, fbos);
349    _mesa_DeleteTextures(1, &pbo_tex);
350    _mesa_DeleteBuffers(1, &pbo);
351
352    _mesa_meta_end(ctx);
353
354    return success;
355 }