meta: Use _mesa_bind_framebuffers instead of _mesa_BindFramebuffer
[mesa.git] / src / mesa / drivers / common / meta_copy_image.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 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
25 #include "glheader.h"
26 #include "context.h"
27 #include "enums.h"
28 #include "imports.h"
29 #include "macros.h"
30 #include "teximage.h"
31 #include "texobj.h"
32 #include "fbobject.h"
33 #include "buffers.h"
34 #include "state.h"
35 #include "mtypes.h"
36 #include "meta.h"
37
38 /**
39 * Create a texture image that wraps a renderbuffer.
40 */
41 static struct gl_texture_image *
42 wrap_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
43 {
44 GLenum texTarget;
45 struct gl_texture_object *texObj;
46 struct gl_texture_image *texImage;
47
48 if (rb->NumSamples > 1)
49 texTarget = GL_TEXTURE_2D_MULTISAMPLE;
50 else
51 texTarget = GL_TEXTURE_2D;
52
53 /* Texture ID is not significant since it never goes into the hash table */
54 texObj = ctx->Driver.NewTextureObject(ctx, 0, texTarget);
55 assert(texObj);
56 if (!texObj)
57 return NULL;
58
59 texImage = _mesa_get_tex_image(ctx, texObj, texTarget, 0);
60 assert(texImage);
61 if (!texImage)
62 return NULL;
63
64 if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
65 _mesa_problem(ctx, "Failed to create texture from renderbuffer");
66 return NULL;
67 }
68
69 if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
70 rb->NeedsFinishRenderTexture = true;
71 ctx->Driver.FinishRenderTexture(ctx, rb);
72 }
73
74 return texImage;
75 }
76
77
78 /* This function makes a texture view without bothering with all of the API
79 * checks. Most of them are the same for CopyTexSubImage so checking would
80 * be redundant. The one major difference is that we don't check for
81 * whether the texture is immutable or not. However, since the view will
82 * be created and then immediately destroyed, this should not be a problem.
83 */
84 static bool
85 make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
86 struct gl_texture_image **view_tex_image, GLuint *view_tex_name,
87 GLenum internal_format)
88 {
89 struct gl_texture_object *tex_obj = tex_image->TexObject;
90 struct gl_texture_object *view_tex_obj;
91 mesa_format tex_format;
92
93 /* Set up the new texture object */
94 _mesa_GenTextures(1, view_tex_name);
95 view_tex_obj = _mesa_lookup_texture(ctx, *view_tex_name);
96 if (!view_tex_obj)
97 return false;
98
99 tex_format = _mesa_choose_texture_format(ctx, view_tex_obj, tex_obj->Target,
100 0, internal_format,
101 GL_NONE, GL_NONE);
102
103 if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format,
104 tex_image->Width, tex_image->Height,
105 tex_image->Depth, 0)) {
106 _mesa_DeleteTextures(1, view_tex_name);
107 *view_tex_name = 0;
108 return false;
109 }
110
111 assert(tex_obj->Target != 0);
112 assert(tex_obj->TargetIndex < NUM_TEXTURE_TARGETS);
113
114 view_tex_obj->Target = tex_obj->Target;
115 view_tex_obj->TargetIndex = tex_obj->TargetIndex;
116
117 *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0);
118
119 if (!*view_tex_image) {
120 _mesa_DeleteTextures(1, view_tex_name);
121 *view_tex_name = 0;
122 return false;
123 }
124
125 _mesa_init_teximage_fields(ctx, *view_tex_image,
126 tex_image->Width, tex_image->Height,
127 tex_image->Depth,
128 0, internal_format, tex_format);
129
130 view_tex_obj->MinLevel = tex_image->Level;
131 view_tex_obj->NumLevels = 1;
132 view_tex_obj->MinLayer = tex_obj->MinLayer;
133 view_tex_obj->NumLayers = tex_obj->NumLayers;
134 view_tex_obj->Immutable = tex_obj->Immutable;
135 view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels;
136
137 if (ctx->Driver.TextureView != NULL &&
138 !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) {
139 _mesa_DeleteTextures(1, view_tex_name);
140 *view_tex_name = 0;
141 return false; /* driver recorded error */
142 }
143
144 return true;
145 }
146
147 /** A partial implementation of glCopyImageSubData
148 *
149 * This is a partial implementation of glCopyImageSubData that works only
150 * if both textures are uncompressed and the destination texture is
151 * renderable. It uses a slight abuse of a texture view (see make_view) to
152 * turn the source texture into the destination texture type and then uses
153 * _mesa_meta_BlitFramebuffers to do the copy.
154 */
155 bool
156 _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
157 struct gl_texture_image *src_tex_image,
158 struct gl_renderbuffer *src_renderbuffer,
159 int src_x, int src_y, int src_z,
160 struct gl_texture_image *dst_tex_image,
161 struct gl_renderbuffer *dst_renderbuffer,
162 int dst_x, int dst_y, int dst_z,
163 int src_width, int src_height)
164 {
165 mesa_format src_format, dst_format;
166 GLint src_internal_format, dst_internal_format;
167 GLuint src_view_texture = 0;
168 struct gl_texture_image *src_view_tex_image;
169 GLuint fbos[2];
170 struct gl_framebuffer *readFb;
171 struct gl_framebuffer *drawFb;
172 bool success = false;
173 GLbitfield mask;
174 GLenum status, attachment;
175
176 if (src_renderbuffer) {
177 src_format = src_renderbuffer->Format;
178 src_internal_format = src_renderbuffer->InternalFormat;
179 } else {
180 assert(src_tex_image);
181 src_format = src_tex_image->TexFormat;
182 src_internal_format = src_tex_image->InternalFormat;
183 }
184
185 if (dst_renderbuffer) {
186 dst_format = dst_renderbuffer->Format;
187 dst_internal_format = dst_renderbuffer->InternalFormat;
188 } else {
189 assert(dst_tex_image);
190 dst_format = dst_tex_image->TexFormat;
191 dst_internal_format = dst_tex_image->InternalFormat;
192 }
193
194 if (_mesa_is_format_compressed(src_format))
195 return false;
196
197 if (_mesa_is_format_compressed(dst_format))
198 return false;
199
200 if (src_internal_format == dst_internal_format) {
201 src_view_tex_image = src_tex_image;
202 } else {
203 if (src_renderbuffer) {
204 assert(src_tex_image == NULL);
205 src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer);
206 }
207 if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture,
208 dst_internal_format))
209 goto cleanup;
210 }
211
212 /* We really only need to stash the bound framebuffers and scissor. */
213 _mesa_meta_begin(ctx, MESA_META_SCISSOR);
214
215 _mesa_CreateFramebuffers(2, fbos);
216 readFb = _mesa_lookup_framebuffer(ctx, fbos[0]);
217 assert(readFb != NULL && readFb->Name == fbos[0]);
218
219 drawFb = _mesa_lookup_framebuffer(ctx, fbos[1]);
220 assert(drawFb != NULL && drawFb->Name == fbos[1]);
221
222 _mesa_bind_framebuffers(ctx, drawFb, readFb);
223
224 switch (_mesa_get_format_base_format(src_format)) {
225 case GL_DEPTH_COMPONENT:
226 attachment = GL_DEPTH_ATTACHMENT;
227 mask = GL_DEPTH_BUFFER_BIT;
228 break;
229 case GL_DEPTH_STENCIL:
230 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
231 mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
232 break;
233 case GL_STENCIL_INDEX:
234 attachment = GL_STENCIL_ATTACHMENT;
235 mask = GL_STENCIL_BUFFER_BIT;
236 break;
237 default:
238 attachment = GL_COLOR_ATTACHMENT0;
239 mask = GL_COLOR_BUFFER_BIT;
240 _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
241 _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0);
242 }
243
244 if (src_view_tex_image) {
245 /* Prefer the tex image because, even if we have a renderbuffer, we may
246 * have had to wrap it in a texture view.
247 */
248 _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, attachment,
249 src_view_tex_image, src_z);
250 } else {
251 _mesa_framebuffer_renderbuffer(ctx, ctx->ReadBuffer, attachment,
252 src_renderbuffer);
253 }
254
255 status = _mesa_check_framebuffer_status(ctx, ctx->ReadBuffer);
256 if (status != GL_FRAMEBUFFER_COMPLETE)
257 goto meta_end;
258
259 if (dst_renderbuffer) {
260 _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, attachment,
261 dst_renderbuffer);
262 } else {
263 _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, attachment,
264 dst_tex_image, dst_z);
265 }
266
267 status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer);
268 if (status != GL_FRAMEBUFFER_COMPLETE)
269 goto meta_end;
270
271 /* Since we've bound a new draw framebuffer, we need to update its
272 * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to
273 * be correct.
274 */
275 _mesa_update_state(ctx);
276
277 /* We skip the core BlitFramebuffer checks for format consistency.
278 * We have already created views to ensure that the texture formats
279 * match.
280 */
281 ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
282 src_x, src_y,
283 src_x + src_width, src_y + src_height,
284 dst_x, dst_y,
285 dst_x + src_width, dst_y + src_height,
286 mask, GL_NEAREST);
287
288 success = true;
289
290 meta_end:
291 _mesa_DeleteFramebuffers(2, fbos);
292 _mesa_meta_end(ctx);
293
294 cleanup:
295 _mesa_DeleteTextures(1, &src_view_texture);
296
297 /* If we got a renderbuffer source, delete the temporary texture */
298 if (src_renderbuffer && src_tex_image)
299 ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject);
300
301 return success;
302 }