VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/surface.c@ 32061

Last change on this file since 32061 was 32061, checked in by vboxsync, 14 years ago

wddm/3d: wine: shared resource handling fixes

  • Property svn:eol-style set to native
File size: 191.8 KB
Line 
1/*
2 * IWineD3DSurface Implementation
3 *
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007-2008 Henri Verbeet
12 * Copyright 2006-2008 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 */
29
30/*
31 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
32 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
33 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
34 * a choice of LGPL license versions is made available with the language indicating
35 * that LGPLv2 or any later version may be used, or where a choice of which version
36 * of the LGPL is applied is otherwise unspecified.
37 */
38
39#include "config.h"
40#include "wine/port.h"
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
44WINE_DECLARE_DEBUG_CHANNEL(d3d);
45
46#define GLINFO_LOCATION (*gl_info)
47
48static void surface_cleanup(IWineD3DSurfaceImpl *This)
49{
50 IWineD3DDeviceImpl *device = This->resource.device;
51 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
52 struct wined3d_context *context = NULL;
53 renderbuffer_entry_t *entry, *entry2;
54
55 TRACE("(%p) : Cleaning up.\n", This);
56
57 /* Need a context to destroy the texture. Use the currently active render
58 * target, but only if the primary render target exists. Otherwise
59 * lastActiveRenderTarget is garbage. When destroying the primary render
60 * target, Uninit3D() will activate a context before doing anything. */
61 if (device->render_targets && device->render_targets[0])
62 {
63 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
64 }
65
66 ENTER_GL();
67
68 if (This->texture_name)
69 {
70 /* Release the OpenGL texture. */
71 TRACE("Deleting texture %u.\n", This->texture_name);
72 glDeleteTextures(1, &This->texture_name);
73 }
74
75 if (This->Flags & SFLAG_PBO)
76 {
77 /* Delete the PBO. */
78 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
79 }
80
81 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
82 {
83 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
84 HeapFree(GetProcessHeap(), 0, entry);
85 }
86
87 LEAVE_GL();
88
89 if (This->Flags & SFLAG_DIBSECTION)
90 {
91 /* Release the DC. */
92 SelectObject(This->hDC, This->dib.holdbitmap);
93 DeleteDC(This->hDC);
94 /* Release the DIB section. */
95 DeleteObject(This->dib.DIBsection);
96 This->dib.bitmap_data = NULL;
97 This->resource.allocatedMemory = NULL;
98 }
99
100 if (This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
101 if (This->overlay_dest) list_remove(&This->overlay_entry);
102
103 HeapFree(GetProcessHeap(), 0, This->palette9);
104
105 resource_cleanup((IWineD3DResource *)This);
106
107 if (context) context_release(context);
108}
109
110UINT surface_calculate_size(const struct wined3d_format_desc *format_desc, UINT alignment, UINT width, UINT height)
111{
112 UINT size;
113
114 if (format_desc->format == WINED3DFMT_UNKNOWN)
115 {
116 size = 0;
117 }
118 else if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
119 {
120 UINT row_block_count = (width + format_desc->block_width - 1) / format_desc->block_width;
121 UINT row_count = (height + format_desc->block_height - 1) / format_desc->block_height;
122 size = row_count * row_block_count * format_desc->block_byte_count;
123 }
124 else
125 {
126 /* The pitch is a multiple of 4 bytes. */
127 size = height * (((width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1));
128 }
129
130 if (format_desc->heightscale != 0.0f) size *= format_desc->heightscale;
131
132 return size;
133}
134
135struct blt_info
136{
137 GLenum binding;
138 GLenum bind_target;
139 enum tex_types tex_type;
140 GLfloat coords[4][3];
141};
142
143struct float_rect
144{
145 float l;
146 float t;
147 float r;
148 float b;
149};
150
151static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
152{
153 f->l = ((r->left * 2.0f) / w) - 1.0f;
154 f->t = ((r->top * 2.0f) / h) - 1.0f;
155 f->r = ((r->right * 2.0f) / w) - 1.0f;
156 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
157}
158
159static void surface_get_blt_info(GLenum target, const RECT *rect_in, GLsizei w, GLsizei h, struct blt_info *info)
160{
161 GLfloat (*coords)[3] = info->coords;
162 RECT rect;
163 struct float_rect f;
164
165 if (rect_in)
166 rect = *rect_in;
167 else
168 {
169 rect.left = 0;
170 rect.top = h;
171 rect.right = w;
172 rect.bottom = 0;
173 }
174
175 switch (target)
176 {
177 default:
178 FIXME("Unsupported texture target %#x\n", target);
179 /* Fall back to GL_TEXTURE_2D */
180 case GL_TEXTURE_2D:
181 info->binding = GL_TEXTURE_BINDING_2D;
182 info->bind_target = GL_TEXTURE_2D;
183 info->tex_type = tex_2d;
184 coords[0][0] = (float)rect.left / w;
185 coords[0][1] = (float)rect.top / h;
186 coords[0][2] = 0.0f;
187
188 coords[1][0] = (float)rect.right / w;
189 coords[1][1] = (float)rect.top / h;
190 coords[1][2] = 0.0f;
191
192 coords[2][0] = (float)rect.left / w;
193 coords[2][1] = (float)rect.bottom / h;
194 coords[2][2] = 0.0f;
195
196 coords[3][0] = (float)rect.right / w;
197 coords[3][1] = (float)rect.bottom / h;
198 coords[3][2] = 0.0f;
199 break;
200
201 case GL_TEXTURE_RECTANGLE_ARB:
202 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
203 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
204 info->tex_type = tex_rect;
205 coords[0][0] = rect.left; coords[0][1] = rect.top; coords[0][2] = 0.0f;
206 coords[1][0] = rect.right; coords[1][1] = rect.top; coords[1][2] = 0.0f;
207 coords[2][0] = rect.left; coords[2][1] = rect.bottom; coords[2][2] = 0.0f;
208 coords[3][0] = rect.right; coords[3][1] = rect.bottom; coords[3][2] = 0.0f;
209 break;
210
211 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
212 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
213 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
214 info->tex_type = tex_cube;
215 cube_coords_float(&rect, w, h, &f);
216
217 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
218 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
219 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
220 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
221 break;
222
223 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
224 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
225 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
226 info->tex_type = tex_cube;
227 cube_coords_float(&rect, w, h, &f);
228
229 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
230 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
231 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
232 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
233 break;
234
235 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
236 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
237 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
238 info->tex_type = tex_cube;
239 cube_coords_float(&rect, w, h, &f);
240
241 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
242 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
243 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
244 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
245 break;
246
247 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
248 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
249 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
250 info->tex_type = tex_cube;
251 cube_coords_float(&rect, w, h, &f);
252
253 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
254 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
255 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
256 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
257 break;
258
259 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
260 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
261 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
262 info->tex_type = tex_cube;
263 cube_coords_float(&rect, w, h, &f);
264
265 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
266 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
267 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
268 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
269 break;
270
271 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
272 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
273 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
274 info->tex_type = tex_cube;
275 cube_coords_float(&rect, w, h, &f);
276
277 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
278 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
279 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
280 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
281 break;
282 }
283}
284
285static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
286{
287 if (rect_in)
288 *rect_out = *rect_in;
289 else
290 {
291 rect_out->left = 0;
292 rect_out->top = 0;
293 rect_out->right = This->currentDesc.Width;
294 rect_out->bottom = This->currentDesc.Height;
295 }
296}
297
298/* GL locking and context activation is done by the caller */
299void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
300{
301 IWineD3DBaseTextureImpl *texture;
302 struct blt_info info;
303
304 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
305
306 glEnable(info.bind_target);
307 checkGLcall("glEnable(bind_target)");
308
309 /* Bind the texture */
310 glBindTexture(info.bind_target, src_surface->texture_name);
311 checkGLcall("glBindTexture");
312
313 /* Filtering for StretchRect */
314 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
315 wined3d_gl_mag_filter(magLookup, Filter));
316 checkGLcall("glTexParameteri");
317 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
318 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
319 checkGLcall("glTexParameteri");
320 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
321 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
322 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
323 checkGLcall("glTexEnvi");
324
325 /* Draw a quad */
326 glBegin(GL_TRIANGLE_STRIP);
327 glTexCoord3fv(info.coords[0]);
328 glVertex2i(dst_rect->left, dst_rect->top);
329
330 glTexCoord3fv(info.coords[1]);
331 glVertex2i(dst_rect->right, dst_rect->top);
332
333 glTexCoord3fv(info.coords[2]);
334 glVertex2i(dst_rect->left, dst_rect->bottom);
335
336 glTexCoord3fv(info.coords[3]);
337 glVertex2i(dst_rect->right, dst_rect->bottom);
338 glEnd();
339
340 /* Unbind the texture */
341 glBindTexture(info.bind_target, 0);
342 checkGLcall("glBindTexture(info->bind_target, 0)");
343
344 /* We changed the filtering settings on the texture. Inform the
345 * container about this to get the filters reset properly next draw. */
346 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DBaseTexture, (void **)&texture)))
347 {
348 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
349 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
350 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
351 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
352 }
353}
354
355HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
356 UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
357 UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format,
358 WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops
359#ifdef VBOXWDDM
360 , HANDLE *shared_handle
361 , void *pvClientMem
362#endif
363 )
364{
365 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
366 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info);
367 void (*cleanup)(IWineD3DSurfaceImpl *This);
368 unsigned int resource_size;
369 HRESULT hr;
370
371 if (multisample_quality > 0)
372 {
373 FIXME("multisample_quality set to %u, substituting 0\n", multisample_quality);
374 multisample_quality = 0;
375 }
376
377 /* FIXME: Check that the format is supported by the device. */
378
379 resource_size = surface_calculate_size(format_desc, alignment, width, height);
380
381 /* Look at the implementation and set the correct Vtable. */
382 switch (surface_type)
383 {
384 case SURFACE_OPENGL:
385 surface->lpVtbl = &IWineD3DSurface_Vtbl;
386 cleanup = surface_cleanup;
387 break;
388
389 case SURFACE_GDI:
390 surface->lpVtbl = &IWineGDISurface_Vtbl;
391 cleanup = surface_gdi_cleanup;
392 break;
393
394 default:
395 ERR("Requested unknown surface implementation %#x.\n", surface_type);
396 return WINED3DERR_INVALIDCALL;
397 }
398
399 hr = resource_init((IWineD3DResource *)surface, WINED3DRTYPE_SURFACE,
400 device, resource_size, usage, format_desc, pool, parent, parent_ops
401#ifdef VBOXWDDM
402 , shared_handle
403 , pvClientMem
404#endif
405 );
406 if (FAILED(hr))
407 {
408 WARN("Failed to initialize resource, returning %#x.\n", hr);
409 return hr;
410 }
411
412 /* "Standalone" surface. */
413 IWineD3DSurface_SetContainer((IWineD3DSurface *)surface, NULL);
414
415 surface->currentDesc.Width = width;
416 surface->currentDesc.Height = height;
417 surface->currentDesc.MultiSampleType = multisample_type;
418 surface->currentDesc.MultiSampleQuality = multisample_quality;
419 surface->texture_level = level;
420 list_init(&surface->overlays);
421
422 /* Flags */
423 surface->Flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
424#ifdef VBOXWDDM
425 if (pool == WINED3DPOOL_SYSTEMMEM && pvClientMem) surface->Flags |= SFLAG_CLIENTMEM;
426#endif
427 if (discard) surface->Flags |= SFLAG_DISCARD;
428 if (lockable || format == WINED3DFMT_D16_LOCKABLE) surface->Flags |= SFLAG_LOCKABLE;
429
430 /* Quick lockable sanity check.
431 * TODO: remove this after surfaces, usage and lockability have been debugged properly
432 * this function is too deep to need to care about things like this.
433 * Levels need to be checked too, since they all affect what can be done. */
434 switch (pool)
435 {
436 case WINED3DPOOL_SCRATCH:
437 if(!lockable)
438 {
439 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
440 "which are mutually exclusive, setting lockable to TRUE.\n");
441 lockable = TRUE;
442 }
443 break;
444
445 case WINED3DPOOL_SYSTEMMEM:
446 if (!lockable)
447 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
448 break;
449
450 case WINED3DPOOL_MANAGED:
451 if (usage & WINED3DUSAGE_DYNAMIC)
452 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
453 break;
454
455 case WINED3DPOOL_DEFAULT:
456 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
457 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
458 break;
459
460 default:
461 FIXME("Unknown pool %#x.\n", pool);
462 break;
463 };
464
465 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
466 {
467 FIXME("Trying to create a render target that isn't in the default pool.\n");
468 }
469
470 /* Mark the texture as dirty so that it gets loaded first time around. */
471 surface_add_dirty_rect((IWineD3DSurface *)surface, NULL);
472 list_init(&surface->renderbuffers);
473
474 TRACE("surface %p, memory %p, size %u\n", surface, surface->resource.allocatedMemory, surface->resource.size);
475
476 /* Call the private setup routine */
477 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)surface);
478 if (FAILED(hr))
479 {
480 ERR("Private setup failed, returning %#x\n", hr);
481 cleanup(surface);
482 return hr;
483 }
484
485 return hr;
486}
487
488static void surface_force_reload(IWineD3DSurface *iface)
489{
490 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
491
492#if defined(DEBUG_misha) && defined (VBOXWDDM)
493 if (VBOXSHRC_IS_INITIALIZED(This))
494 {
495 Assert(0);
496 }
497#endif
498
499 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
500}
501
502void surface_set_texture_name(IWineD3DSurface *iface, GLuint new_name, BOOL srgb)
503{
504 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
505 GLuint *name;
506 DWORD flag;
507
508 if(srgb)
509 {
510 name = &This->texture_name_srgb;
511 flag = SFLAG_INSRGBTEX;
512 }
513 else
514 {
515 name = &This->texture_name;
516 flag = SFLAG_INTEXTURE;
517 }
518
519 TRACE("(%p) : setting texture name %u\n", This, new_name);
520
521 if (!*name && new_name)
522 {
523 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
524 * surface has no texture name yet. See if we can get rid of this. */
525 if (This->Flags & flag)
526 ERR("Surface has SFLAG_INTEXTURE set, but no texture name\n");
527 IWineD3DSurface_ModifyLocation(iface, flag, FALSE);
528 }
529
530#ifdef VBOXWDDM
531 if (VBOXSHRC_IS_SHARED(This))
532 {
533 VBOXSHRC_SET_SHAREHANDLE(This, new_name);
534 }
535#endif
536 *name = new_name;
537 surface_force_reload(iface);
538}
539
540void surface_set_texture_target(IWineD3DSurface *iface, GLenum target)
541{
542 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
543
544 TRACE("(%p) : setting target %#x\n", This, target);
545
546 if (This->texture_target != target)
547 {
548 if (target == GL_TEXTURE_RECTANGLE_ARB)
549 {
550 This->Flags &= ~SFLAG_NORMCOORD;
551 }
552 else if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
553 {
554 This->Flags |= SFLAG_NORMCOORD;
555 }
556 }
557 This->texture_target = target;
558 surface_force_reload(iface);
559}
560
561/* Context activation is done by the caller. */
562static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This, BOOL srgb) {
563 DWORD active_sampler;
564
565 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
566 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
567 * gl states. The current texture unit should always be a valid one.
568 *
569 * To be more specific, this is tricky because we can implicitly be called
570 * from sampler() in state.c. This means we can't touch anything other than
571 * whatever happens to be the currently active texture, or we would risk
572 * marking already applied sampler states dirty again.
573 *
574 * TODO: Track the current active texture per GL context instead of using glGet
575 */
576 GLint active_texture=GL_TEXTURE0_ARB;
577 ENTER_GL();
578 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
579 LEAVE_GL();
580 active_sampler = This->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
581
582 if (active_sampler != WINED3D_UNMAPPED_STAGE)
583 {
584 IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_SAMPLER(active_sampler));
585 }
586 IWineD3DSurface_BindTexture((IWineD3DSurface *)This, srgb);
587}
588
589/* This function checks if the primary render target uses the 8bit paletted format. */
590static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
591{
592 if (device->render_targets && device->render_targets[0]) {
593 IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
594 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
595 && (render_target->resource.format_desc->format == WINED3DFMT_P8_UINT))
596 return TRUE;
597 }
598 return FALSE;
599}
600
601/* This call just downloads data, the caller is responsible for binding the
602 * correct texture. */
603/* Context activation is done by the caller. */
604static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
605{
606 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
607
608 /* Only support read back of converted P8 surfaces */
609 if (This->Flags & SFLAG_CONVERTED && format_desc->format != WINED3DFMT_P8_UINT)
610 {
611 FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(format_desc->format));
612 return;
613 }
614
615 ENTER_GL();
616
617 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
618 {
619 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
620 This, This->texture_level, format_desc->glFormat, format_desc->glType,
621 This->resource.allocatedMemory);
622
623 if (This->Flags & SFLAG_PBO)
624 {
625 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
626 checkGLcall("glBindBufferARB");
627 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
628 checkGLcall("glGetCompressedTexImageARB");
629 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
630 checkGLcall("glBindBufferARB");
631 }
632 else
633 {
634 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
635 This->texture_level, This->resource.allocatedMemory));
636 checkGLcall("glGetCompressedTexImageARB");
637 }
638
639 LEAVE_GL();
640 } else {
641 void *mem;
642 GLenum format = format_desc->glFormat;
643 GLenum type = format_desc->glType;
644 int src_pitch = 0;
645 int dst_pitch = 0;
646
647 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
648 if (format_desc->format == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
649 {
650 format = GL_ALPHA;
651 type = GL_UNSIGNED_BYTE;
652 }
653
654 if (This->Flags & SFLAG_NONPOW2) {
655 unsigned char alignment = This->resource.device->surface_alignment;
656 src_pitch = format_desc->byte_count * This->pow2Width;
657 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
658 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
659 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
660 } else {
661 mem = This->resource.allocatedMemory;
662 }
663
664 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
665 This, This->texture_level, format, type, mem);
666
667 if(This->Flags & SFLAG_PBO) {
668 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
669 checkGLcall("glBindBufferARB");
670
671 glGetTexImage(This->texture_target, This->texture_level, format, type, NULL);
672 checkGLcall("glGetTexImage");
673
674 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
675 checkGLcall("glBindBufferARB");
676 } else {
677 glGetTexImage(This->texture_target, This->texture_level, format, type, mem);
678 checkGLcall("glGetTexImage");
679 }
680 LEAVE_GL();
681
682 if (This->Flags & SFLAG_NONPOW2) {
683 const BYTE *src_data;
684 BYTE *dst_data;
685 UINT y;
686 /*
687 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
688 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
689 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
690 *
691 * We're doing this...
692 *
693 * instead of boxing the texture :
694 * |<-texture width ->| -->pow2width| /\
695 * |111111111111111111| | |
696 * |222 Texture 222222| boxed empty | texture height
697 * |3333 Data 33333333| | |
698 * |444444444444444444| | \/
699 * ----------------------------------- |
700 * | boxed empty | boxed empty | pow2height
701 * | | | \/
702 * -----------------------------------
703 *
704 *
705 * we're repacking the data to the expected texture width
706 *
707 * |<-texture width ->| -->pow2width| /\
708 * |111111111111111111222222222222222| |
709 * |222333333333333333333444444444444| texture height
710 * |444444 | |
711 * | | \/
712 * | | |
713 * | empty | pow2height
714 * | | \/
715 * -----------------------------------
716 *
717 * == is the same as
718 *
719 * |<-texture width ->| /\
720 * |111111111111111111|
721 * |222222222222222222|texture height
722 * |333333333333333333|
723 * |444444444444444444| \/
724 * --------------------
725 *
726 * this also means that any references to allocatedMemory should work with the data as if were a
727 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
728 *
729 * internally the texture is still stored in a boxed format so any references to textureName will
730 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
731 *
732 * Performance should not be an issue, because applications normally do not lock the surfaces when
733 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
734 * and doesn't have to be re-read.
735 */
736 src_data = mem;
737 dst_data = This->resource.allocatedMemory;
738 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
739 for (y = 1 ; y < This->currentDesc.Height; y++) {
740 /* skip the first row */
741 src_data += src_pitch;
742 dst_data += dst_pitch;
743 memcpy(dst_data, src_data, dst_pitch);
744 }
745
746 HeapFree(GetProcessHeap(), 0, mem);
747 }
748 }
749
750 /* Surface has now been downloaded */
751 This->Flags |= SFLAG_INSYSMEM;
752}
753
754/* This call just uploads data, the caller is responsible for binding the
755 * correct texture. */
756/* Context activation is done by the caller. */
757static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
758 const struct wined3d_format_desc *format_desc, BOOL srgb, const GLvoid *data)
759{
760 GLsizei width = This->currentDesc.Width;
761 GLsizei height = This->currentDesc.Height;
762 GLenum internal;
763
764 if (srgb)
765 {
766 internal = format_desc->glGammaInternal;
767 }
768 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
769 && surface_is_offscreen((IWineD3DSurface *)This))
770 {
771 internal = format_desc->rtInternal;
772 }
773 else
774 {
775 internal = format_desc->glInternal;
776 }
777
778 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
779 This, internal, width, height, format_desc->glFormat, format_desc->glType, data);
780 TRACE("target %#x, level %u, resource size %u.\n",
781 This->texture_target, This->texture_level, This->resource.size);
782
783 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
784
785 ENTER_GL();
786
787 if (This->Flags & SFLAG_PBO)
788 {
789 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
790 checkGLcall("glBindBufferARB");
791
792 TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
793 data = NULL;
794 }
795
796 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
797 {
798 TRACE("Calling glCompressedTexSubImage2DARB.\n");
799
800 GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
801 0, 0, width, height, internal, This->resource.size, data));
802 checkGLcall("glCompressedTexSubImage2DARB");
803 }
804 else
805 {
806 TRACE("Calling glTexSubImage2D.\n");
807
808 glTexSubImage2D(This->texture_target, This->texture_level,
809 0, 0, width, height, format_desc->glFormat, format_desc->glType, data);
810 checkGLcall("glTexSubImage2D");
811 }
812
813 if (This->Flags & SFLAG_PBO)
814 {
815 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
816 checkGLcall("glBindBufferARB");
817 }
818
819 LEAVE_GL();
820
821 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
822 {
823 IWineD3DDeviceImpl *device = This->resource.device;
824 unsigned int i;
825
826 for (i = 0; i < device->numContexts; ++i)
827 {
828 context_surface_update(device->contexts[i], This);
829 }
830 }
831}
832
833/* This call just allocates the texture, the caller is responsible for binding
834 * the correct texture. */
835/* Context activation is done by the caller. */
836static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
837 const struct wined3d_format_desc *format_desc, BOOL srgb)
838{
839 BOOL enable_client_storage = FALSE;
840 GLsizei width = This->pow2Width;
841 GLsizei height = This->pow2Height;
842 const BYTE *mem = NULL;
843 GLenum internal;
844
845 if (srgb)
846 {
847 internal = format_desc->glGammaInternal;
848 }
849 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
850 && surface_is_offscreen((IWineD3DSurface *)This))
851 {
852 internal = format_desc->rtInternal;
853 }
854 else
855 {
856 internal = format_desc->glInternal;
857 }
858
859 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
860
861 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
862 This, This->texture_target, This->texture_level, debug_d3dformat(format_desc->format),
863 internal, width, height, format_desc->glFormat, format_desc->glType);
864
865 ENTER_GL();
866
867 if (gl_info->supported[APPLE_CLIENT_STORAGE])
868 {
869 if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
870 /* In some cases we want to disable client storage.
871 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
872 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
873 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
874 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
875 */
876 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
877 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
878 This->Flags &= ~SFLAG_CLIENT;
879 enable_client_storage = TRUE;
880 } else {
881 This->Flags |= SFLAG_CLIENT;
882
883 /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
884 * it might point into a pbo. Instead use heapMemory, but get the alignment right.
885 */
886 mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
887 }
888 }
889
890#ifdef VBOXWDDM
891 if (!VBOXSHRC_IS_SHARED_OPENED(This))
892#endif
893 {
894 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED && mem)
895 {
896 GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
897 internal, width, height, 0, This->resource.size, mem));
898 }
899 else
900 {
901 glTexImage2D(This->texture_target, This->texture_level,
902 internal, width, height, 0, format_desc->glFormat, format_desc->glType, mem);
903 checkGLcall("glTexImage2D");
904 }
905 }
906
907 if(enable_client_storage) {
908 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
909 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
910 }
911 LEAVE_GL();
912}
913
914/* In D3D the depth stencil dimensions have to be greater than or equal to the
915 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
916/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
917/* GL locking is done by the caller */
918void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
919 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
920 const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
921 renderbuffer_entry_t *entry;
922 GLuint renderbuffer = 0;
923 unsigned int src_width, src_height;
924
925 src_width = This->pow2Width;
926 src_height = This->pow2Height;
927
928 /* A depth stencil smaller than the render target is not valid */
929 if (width > src_width || height > src_height) return;
930
931 /* Remove any renderbuffer set if the sizes match */
932 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
933 || (width == src_width && height == src_height))
934 {
935 This->current_renderbuffer = NULL;
936 return;
937 }
938
939 /* Look if we've already got a renderbuffer of the correct dimensions */
940 LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
941 if (entry->width == width && entry->height == height) {
942 renderbuffer = entry->id;
943 This->current_renderbuffer = entry;
944 break;
945 }
946 }
947
948 if (!renderbuffer) {
949 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
950 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
951 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
952 This->resource.format_desc->glInternal, width, height);
953
954 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
955 entry->width = width;
956 entry->height = height;
957 entry->id = renderbuffer;
958 list_add_head(&This->renderbuffers, &entry->entry);
959
960 This->current_renderbuffer = entry;
961 }
962
963 checkGLcall("set_compatible_renderbuffer");
964}
965
966GLenum surface_get_gl_buffer(IWineD3DSurface *iface)
967{
968 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
969 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *)This->container;
970
971 TRACE("iface %p.\n", iface);
972
973 if (!(This->Flags & SFLAG_SWAPCHAIN))
974 {
975 ERR("Surface %p is not on a swapchain.\n", iface);
976 return GL_NONE;
977 }
978
979 if (swapchain->backBuffer && swapchain->backBuffer[0] == iface)
980 {
981 if (swapchain->render_to_fbo)
982 {
983 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
984 return GL_COLOR_ATTACHMENT0;
985 }
986 TRACE("Returning GL_BACK\n");
987 return GL_BACK;
988 }
989 else if (swapchain->frontBuffer == iface)
990 {
991 TRACE("Returning GL_FRONT\n");
992 return GL_FRONT;
993 }
994
995 FIXME("Higher back buffer, returning GL_BACK\n");
996 return GL_BACK;
997}
998
999#ifdef VBOXWDDM
1000static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect);
1001#endif
1002
1003/* Slightly inefficient way to handle multiple dirty rects but it works :) */
1004void surface_add_dirty_rect(IWineD3DSurface *iface, const RECT *dirty_rect)
1005{
1006 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1007 IWineD3DBaseTexture *baseTexture = NULL;
1008
1009 if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
1010 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */);
1011
1012 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
1013
1014 if (dirty_rect)
1015 {
1016 This->dirtyRect.left = min(This->dirtyRect.left, dirty_rect->left);
1017 This->dirtyRect.top = min(This->dirtyRect.top, dirty_rect->top);
1018 This->dirtyRect.right = max(This->dirtyRect.right, dirty_rect->right);
1019 This->dirtyRect.bottom = max(This->dirtyRect.bottom, dirty_rect->bottom);
1020 }
1021 else
1022 {
1023 This->dirtyRect.left = 0;
1024 This->dirtyRect.top = 0;
1025 This->dirtyRect.right = This->currentDesc.Width;
1026 This->dirtyRect.bottom = This->currentDesc.Height;
1027 }
1028
1029 TRACE("(%p) : Dirty: yes, Rect:(%d, %d, %d, %d)\n", This, This->dirtyRect.left,
1030 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1031
1032 /* if the container is a basetexture then mark it dirty. */
1033 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)))
1034 {
1035 TRACE("Passing to container\n");
1036 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1037 IWineD3DBaseTexture_Release(baseTexture);
1038 }
1039}
1040
1041static BOOL surface_convert_color_to_argb(IWineD3DSurfaceImpl *This, DWORD color, DWORD *argb_color)
1042{
1043 IWineD3DDeviceImpl *device = This->resource.device;
1044
1045 switch(This->resource.format_desc->format)
1046 {
1047 case WINED3DFMT_P8_UINT:
1048 {
1049 DWORD alpha;
1050
1051 if (primary_render_target_is_p8(device))
1052 alpha = color << 24;
1053 else
1054 alpha = 0xFF000000;
1055
1056 if (This->palette) {
1057 *argb_color = (alpha |
1058 (This->palette->palents[color].peRed << 16) |
1059 (This->palette->palents[color].peGreen << 8) |
1060 (This->palette->palents[color].peBlue));
1061 } else {
1062 *argb_color = alpha;
1063 }
1064 }
1065 break;
1066
1067 case WINED3DFMT_B5G6R5_UNORM:
1068 {
1069 if (color == 0xFFFF) {
1070 *argb_color = 0xFFFFFFFF;
1071 } else {
1072 *argb_color = ((0xFF000000) |
1073 ((color & 0xF800) << 8) |
1074 ((color & 0x07E0) << 5) |
1075 ((color & 0x001F) << 3));
1076 }
1077 }
1078 break;
1079
1080 case WINED3DFMT_B8G8R8_UNORM:
1081 case WINED3DFMT_B8G8R8X8_UNORM:
1082 *argb_color = 0xFF000000 | color;
1083 break;
1084
1085 case WINED3DFMT_B8G8R8A8_UNORM:
1086 *argb_color = color;
1087 break;
1088
1089 default:
1090 ERR("Unhandled conversion from %s to ARGB!\n", debug_d3dformat(This->resource.format_desc->format));
1091 return FALSE;
1092 }
1093 return TRUE;
1094}
1095
1096static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
1097{
1098 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1099 ULONG ref = InterlockedDecrement(&This->resource.ref);
1100 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
1101
1102 if (!ref)
1103 {
1104 surface_cleanup(This);
1105 This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
1106
1107 TRACE("(%p) Released.\n", This);
1108 HeapFree(GetProcessHeap(), 0, This);
1109 }
1110
1111 return ref;
1112}
1113
1114/* ****************************************************
1115 IWineD3DSurface IWineD3DResource parts follow
1116 **************************************************** */
1117
1118void surface_internal_preload(IWineD3DSurface *iface, enum WINED3DSRGB srgb)
1119{
1120 /* TODO: check for locks */
1121 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1122 IWineD3DDeviceImpl *device = This->resource.device;
1123 IWineD3DBaseTexture *baseTexture = NULL;
1124
1125 TRACE("(%p)Checking to see if the container is a base texture\n", This);
1126 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1127 IWineD3DBaseTextureImpl *tex_impl = (IWineD3DBaseTextureImpl *) baseTexture;
1128 TRACE("Passing to container\n");
1129 tex_impl->baseTexture.internal_preload(baseTexture, srgb);
1130 IWineD3DBaseTexture_Release(baseTexture);
1131 } else {
1132 struct wined3d_context *context = NULL;
1133
1134 TRACE("(%p) : About to load surface\n", This);
1135
1136 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1137
1138 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
1139 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
1140 {
1141 if(palette9_changed(This)) {
1142 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1143 /* TODO: This is not necessarily needed with hw palettized texture support */
1144 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1145 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
1146 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1147 }
1148 }
1149
1150 IWineD3DSurface_LoadTexture(iface, srgb == SRGB_SRGB ? TRUE : FALSE);
1151
1152 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
1153 /* Tell opengl to try and keep this texture in video ram (well mostly) */
1154 GLclampf tmp;
1155 tmp = 0.9f;
1156 ENTER_GL();
1157 glPrioritizeTextures(1, &This->texture_name, &tmp);
1158 LEAVE_GL();
1159 }
1160
1161 if (context) context_release(context);
1162 }
1163}
1164
1165static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
1166 surface_internal_preload(iface, SRGB_ANY);
1167}
1168
1169/* Context activation is done by the caller. */
1170static void surface_remove_pbo(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
1171{
1172 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1173 This->resource.allocatedMemory =
1174 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1175
1176 ENTER_GL();
1177 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1178 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
1179 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
1180 checkGLcall("glGetBufferSubDataARB");
1181 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
1182 checkGLcall("glDeleteBuffersARB");
1183 LEAVE_GL();
1184
1185 This->pbo = 0;
1186 This->Flags &= ~SFLAG_PBO;
1187}
1188
1189BOOL surface_init_sysmem(IWineD3DSurface *iface)
1190{
1191 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1192
1193 if(!This->resource.allocatedMemory)
1194 {
1195 This->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + RESOURCE_ALIGNMENT);
1196 if(!This->resource.heapMemory)
1197 {
1198 ERR("Out of memory\n");
1199 return FALSE;
1200 }
1201 This->resource.allocatedMemory =
1202 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1203 }
1204 else
1205 {
1206 memset(This->resource.allocatedMemory, 0, This->resource.size);
1207 }
1208
1209 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
1210 return TRUE;
1211}
1212
1213static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) {
1214 IWineD3DBaseTexture *texture = NULL;
1215 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1216 IWineD3DDeviceImpl *device = This->resource.device;
1217 const struct wined3d_gl_info *gl_info;
1218 renderbuffer_entry_t *entry, *entry2;
1219 struct wined3d_context *context;
1220
1221 TRACE("(%p)\n", iface);
1222
1223 if(This->resource.pool == WINED3DPOOL_DEFAULT) {
1224 /* Default pool resources are supposed to be destroyed before Reset is called.
1225 * Implicit resources stay however. So this means we have an implicit render target
1226 * or depth stencil. The content may be destroyed, but we still have to tear down
1227 * opengl resources, so we cannot leave early.
1228 *
1229 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1230 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1231 * or the depth stencil into an FBO the texture or render buffer will be removed
1232 * and all flags get lost
1233 */
1234 surface_init_sysmem(iface);
1235 } else {
1236 /* Load the surface into system memory */
1237 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1238 IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
1239 }
1240 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1241 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
1242 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1243
1244 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1245 gl_info = context->gl_info;
1246
1247 /* Destroy PBOs, but load them into real sysmem before */
1248 if (This->Flags & SFLAG_PBO)
1249 surface_remove_pbo(This, gl_info);
1250
1251 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1252 * all application-created targets the application has to release the surface
1253 * before calling _Reset
1254 */
1255 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
1256 ENTER_GL();
1257 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1258 LEAVE_GL();
1259 list_remove(&entry->entry);
1260 HeapFree(GetProcessHeap(), 0, entry);
1261 }
1262 list_init(&This->renderbuffers);
1263 This->current_renderbuffer = NULL;
1264
1265 /* If we're in a texture, the texture name belongs to the texture. Otherwise,
1266 * destroy it
1267 */
1268 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **) &texture);
1269 if(!texture) {
1270 ENTER_GL();
1271 glDeleteTextures(1, &This->texture_name);
1272 This->texture_name = 0;
1273 glDeleteTextures(1, &This->texture_name_srgb);
1274 This->texture_name_srgb = 0;
1275 LEAVE_GL();
1276 } else {
1277 IWineD3DBaseTexture_Release(texture);
1278 }
1279
1280 context_release(context);
1281}
1282
1283/* ******************************************************
1284 IWineD3DSurface IWineD3DSurface parts follow
1285 ****************************************************** */
1286
1287/* Read the framebuffer back into the surface */
1288static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
1289{
1290 IWineD3DDeviceImpl *myDevice = This->resource.device;
1291 const struct wined3d_gl_info *gl_info;
1292 struct wined3d_context *context;
1293 BYTE *mem;
1294 GLint fmt;
1295 GLint type;
1296 BYTE *row, *top, *bottom;
1297 int i;
1298 BOOL bpp;
1299 RECT local_rect;
1300 BOOL srcIsUpsideDown;
1301 GLint rowLen = 0;
1302 GLint skipPix = 0;
1303 GLint skipRow = 0;
1304
1305 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1306 static BOOL warned = FALSE;
1307 if(!warned) {
1308 ERR("The application tries to lock the render target, but render target locking is disabled\n");
1309 warned = TRUE;
1310 }
1311 return;
1312 }
1313
1314 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
1315 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
1316 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
1317 * context->last_was_blit set on the unlock.
1318 */
1319 context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1320 gl_info = context->gl_info;
1321
1322 ENTER_GL();
1323
1324 /* Select the correct read buffer, and give some debug output.
1325 * There is no need to keep track of the current read buffer or reset it, every part of the code
1326 * that reads sets the read buffer as desired.
1327 */
1328 if (surface_is_offscreen((IWineD3DSurface *) This))
1329 {
1330 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1331 * Read from the back buffer
1332 */
1333 TRACE("Locking offscreen render target\n");
1334 glReadBuffer(myDevice->offscreenBuffer);
1335 srcIsUpsideDown = TRUE;
1336 }
1337 else
1338 {
1339 /* Onscreen surfaces are always part of a swapchain */
1340 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1341 TRACE("Locking %#x buffer\n", buffer);
1342 glReadBuffer(buffer);
1343 checkGLcall("glReadBuffer");
1344 srcIsUpsideDown = FALSE;
1345 }
1346
1347 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
1348 if(!rect) {
1349 local_rect.left = 0;
1350 local_rect.top = 0;
1351 local_rect.right = This->currentDesc.Width;
1352 local_rect.bottom = This->currentDesc.Height;
1353 } else {
1354 local_rect = *rect;
1355 }
1356 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
1357
1358 switch(This->resource.format_desc->format)
1359 {
1360 case WINED3DFMT_P8_UINT:
1361 {
1362 if(primary_render_target_is_p8(myDevice)) {
1363 /* In case of P8 render targets the index is stored in the alpha component */
1364 fmt = GL_ALPHA;
1365 type = GL_UNSIGNED_BYTE;
1366 mem = dest;
1367 bpp = This->resource.format_desc->byte_count;
1368 } else {
1369 /* GL can't return palettized data, so read ARGB pixels into a
1370 * separate block of memory and convert them into palettized format
1371 * in software. Slow, but if the app means to use palettized render
1372 * targets and locks it...
1373 *
1374 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
1375 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
1376 * for the color channels when palettizing the colors.
1377 */
1378 fmt = GL_RGB;
1379 type = GL_UNSIGNED_BYTE;
1380 pitch *= 3;
1381 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
1382 if(!mem) {
1383 ERR("Out of memory\n");
1384 LEAVE_GL();
1385 return;
1386 }
1387 bpp = This->resource.format_desc->byte_count * 3;
1388 }
1389 }
1390 break;
1391
1392 default:
1393 mem = dest;
1394 fmt = This->resource.format_desc->glFormat;
1395 type = This->resource.format_desc->glType;
1396 bpp = This->resource.format_desc->byte_count;
1397 }
1398
1399 if(This->Flags & SFLAG_PBO) {
1400 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1401 checkGLcall("glBindBufferARB");
1402 if(mem != NULL) {
1403 ERR("mem not null for pbo -- unexpected\n");
1404 mem = NULL;
1405 }
1406 }
1407
1408 /* Save old pixel store pack state */
1409 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
1410 checkGLcall("glGetIntegerv");
1411 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
1412 checkGLcall("glGetIntegerv");
1413 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
1414 checkGLcall("glGetIntegerv");
1415
1416 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1417 glPixelStorei(GL_PACK_ROW_LENGTH, This->currentDesc.Width);
1418 checkGLcall("glPixelStorei");
1419 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
1420 checkGLcall("glPixelStorei");
1421 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
1422 checkGLcall("glPixelStorei");
1423
1424 glReadPixels(local_rect.left, (!srcIsUpsideDown) ? (This->currentDesc.Height - local_rect.bottom) : local_rect.top ,
1425 local_rect.right - local_rect.left,
1426 local_rect.bottom - local_rect.top,
1427 fmt, type, mem);
1428 checkGLcall("glReadPixels");
1429
1430 /* Reset previous pixel store pack state */
1431 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
1432 checkGLcall("glPixelStorei");
1433 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
1434 checkGLcall("glPixelStorei");
1435 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
1436 checkGLcall("glPixelStorei");
1437
1438 if(This->Flags & SFLAG_PBO) {
1439 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1440 checkGLcall("glBindBufferARB");
1441
1442 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
1443 * to get a pointer to it and perform the flipping in software. This is a lot
1444 * faster than calling glReadPixels for each line. In case we want more speed
1445 * we should rerender it flipped in a FBO and read the data back from the FBO. */
1446 if(!srcIsUpsideDown) {
1447 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1448 checkGLcall("glBindBufferARB");
1449
1450 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1451 checkGLcall("glMapBufferARB");
1452 }
1453 }
1454
1455 /* TODO: Merge this with the palettization loop below for P8 targets */
1456 if(!srcIsUpsideDown) {
1457 UINT len, off;
1458 /* glReadPixels returns the image upside down, and there is no way to prevent this.
1459 Flip the lines in software */
1460 len = (local_rect.right - local_rect.left) * bpp;
1461 off = local_rect.left * bpp;
1462
1463 row = HeapAlloc(GetProcessHeap(), 0, len);
1464 if(!row) {
1465 ERR("Out of memory\n");
1466 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
1467 LEAVE_GL();
1468 return;
1469 }
1470
1471 top = mem + pitch * local_rect.top;
1472 bottom = mem + pitch * (local_rect.bottom - 1);
1473 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
1474 memcpy(row, top + off, len);
1475 memcpy(top + off, bottom + off, len);
1476 memcpy(bottom + off, row, len);
1477 top += pitch;
1478 bottom -= pitch;
1479 }
1480 HeapFree(GetProcessHeap(), 0, row);
1481
1482 /* Unmap the temp PBO buffer */
1483 if(This->Flags & SFLAG_PBO) {
1484 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1485 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1486 }
1487 }
1488
1489 LEAVE_GL();
1490 context_release(context);
1491
1492 /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
1493 * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
1494 * the same color but we have no choice.
1495 * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
1496 */
1497 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(myDevice))
1498 {
1499 const PALETTEENTRY *pal = NULL;
1500 DWORD width = pitch / 3;
1501 int x, y, c;
1502
1503 if(This->palette) {
1504 pal = This->palette->palents;
1505 } else {
1506 ERR("Palette is missing, cannot perform inverse palette lookup\n");
1507 HeapFree(GetProcessHeap(), 0, mem);
1508 return ;
1509 }
1510
1511 for(y = local_rect.top; y < local_rect.bottom; y++) {
1512 for(x = local_rect.left; x < local_rect.right; x++) {
1513 /* start lines pixels */
1514 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
1515 const BYTE *green = blue + 1;
1516 const BYTE *red = green + 1;
1517
1518 for(c = 0; c < 256; c++) {
1519 if(*red == pal[c].peRed &&
1520 *green == pal[c].peGreen &&
1521 *blue == pal[c].peBlue)
1522 {
1523 *((BYTE *) dest + y * width + x) = c;
1524 break;
1525 }
1526 }
1527 }
1528 }
1529 HeapFree(GetProcessHeap(), 0, mem);
1530 }
1531}
1532
1533/* Read the framebuffer contents into a texture */
1534static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
1535{
1536 IWineD3DDeviceImpl *device = This->resource.device;
1537 const struct wined3d_gl_info *gl_info;
1538 struct wined3d_context *context;
1539 GLint prevRead;
1540 BOOL alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1541
1542 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
1543 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
1544 * states in the stateblock, and no driver was found yet that had bugs in that regard.
1545 */
1546 context = context_acquire(device, (IWineD3DSurface *) This, CTXUSAGE_RESOURCELOAD);
1547 gl_info = context->gl_info;
1548
1549 surface_bind_and_dirtify(This, srgb);
1550
1551 ENTER_GL();
1552 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1553 LEAVE_GL();
1554
1555 /* Select the correct read buffer, and give some debug output.
1556 * There is no need to keep track of the current read buffer or reset it, every part of the code
1557 * that reads sets the read buffer as desired.
1558 */
1559 if (!surface_is_offscreen((IWineD3DSurface *)This))
1560 {
1561 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1562 TRACE("Locking %#x buffer\n", buffer);
1563
1564 ENTER_GL();
1565 glReadBuffer(buffer);
1566 checkGLcall("glReadBuffer");
1567 LEAVE_GL();
1568 }
1569 else
1570 {
1571 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1572 * Read from the back buffer
1573 */
1574 TRACE("Locking offscreen render target\n");
1575 ENTER_GL();
1576 glReadBuffer(device->offscreenBuffer);
1577 checkGLcall("glReadBuffer");
1578 LEAVE_GL();
1579 }
1580
1581 if (!(This->Flags & alloc_flag))
1582 {
1583 surface_allocate_surface(This, gl_info, This->resource.format_desc, srgb);
1584 This->Flags |= alloc_flag;
1585 }
1586
1587 ENTER_GL();
1588 /* If !SrcIsUpsideDown we should flip the surface.
1589 * This can be done using glCopyTexSubImage2D but this
1590 * is VERY slow, so don't do that. We should prevent
1591 * this code from getting called in such cases or perhaps
1592 * we can use FBOs */
1593
1594 glCopyTexSubImage2D(This->texture_target, This->texture_level,
1595 0, 0, 0, 0, This->currentDesc.Width, This->currentDesc.Height);
1596 checkGLcall("glCopyTexSubImage2D");
1597
1598 glReadBuffer(prevRead);
1599 checkGLcall("glReadBuffer");
1600
1601 LEAVE_GL();
1602
1603 context_release(context);
1604
1605 TRACE("Updated target %d\n", This->texture_target);
1606}
1607
1608/* Context activation is done by the caller. */
1609void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
1610{
1611 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1612 CONVERT_TYPES convert;
1613 struct wined3d_format_desc desc;
1614
1615 if (surface->Flags & alloc_flag) return;
1616
1617 d3dfmt_get_conv(surface, TRUE, TRUE, &desc, &convert);
1618 if(convert != NO_CONVERSION) surface->Flags |= SFLAG_CONVERTED;
1619 else surface->Flags &= ~SFLAG_CONVERTED;
1620
1621 surface_bind_and_dirtify(surface, srgb);
1622 surface_allocate_surface(surface, gl_info, &desc, srgb);
1623 surface->Flags |= alloc_flag;
1624}
1625
1626static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
1627{
1628 IWineD3DDeviceImpl *device = This->resource.device;
1629 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1630
1631 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
1632 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
1633 * changed
1634 */
1635 if(!(This->Flags & SFLAG_DYNLOCK)) {
1636 This->lockCount++;
1637 /* MAXLOCKCOUNT is defined in wined3d_private.h */
1638 if(This->lockCount > MAXLOCKCOUNT) {
1639 TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
1640 This->Flags |= SFLAG_DYNLOCK;
1641 }
1642 }
1643
1644 /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
1645 * Also don't create a PBO for systemmem surfaces.
1646 */
1647 if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->Flags & SFLAG_DYNLOCK)
1648 && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
1649 && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
1650 {
1651 GLenum error;
1652 struct wined3d_context *context;
1653
1654 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1655 ENTER_GL();
1656
1657 GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
1658 error = glGetError();
1659 if(This->pbo == 0 || error != GL_NO_ERROR) {
1660 ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
1661 }
1662
1663 TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
1664
1665 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1666 checkGLcall("glBindBufferARB");
1667
1668 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
1669 checkGLcall("glBufferDataARB");
1670
1671 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1672 checkGLcall("glBindBufferARB");
1673
1674 /* We don't need the system memory anymore and we can't even use it for PBOs */
1675 if(!(This->Flags & SFLAG_CLIENT)) {
1676 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
1677 This->resource.heapMemory = NULL;
1678 }
1679 This->resource.allocatedMemory = NULL;
1680 This->Flags |= SFLAG_PBO;
1681 LEAVE_GL();
1682 context_release(context);
1683 }
1684 else if (!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO))
1685 {
1686 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
1687 * or a pbo to map
1688 */
1689 if(!This->resource.heapMemory) {
1690 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1691 }
1692 This->resource.allocatedMemory =
1693 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1694 if(This->Flags & SFLAG_INSYSMEM) {
1695 ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
1696 }
1697 }
1698}
1699
1700static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
1701 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1702 IWineD3DDeviceImpl *myDevice = This->resource.device;
1703 const RECT *pass_rect = pRect;
1704
1705 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1706
1707 /* This is also done in the base class, but we have to verify this before loading any data from
1708 * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1709 * may interfere, and all other bad things may happen
1710 */
1711 if (This->Flags & SFLAG_LOCKED) {
1712 WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1713 return WINED3DERR_INVALIDCALL;
1714 }
1715 This->Flags |= SFLAG_LOCKED;
1716
1717 if (!(This->Flags & SFLAG_LOCKABLE))
1718 {
1719 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
1720 }
1721
1722 if (Flags & WINED3DLOCK_DISCARD) {
1723 /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1724 TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1725 surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1726 This->Flags |= SFLAG_INSYSMEM;
1727 goto lock_end;
1728 }
1729
1730 if (This->Flags & SFLAG_INSYSMEM) {
1731 TRACE("Local copy is up to date, not downloading data\n");
1732 surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1733 goto lock_end;
1734 }
1735
1736 /* IWineD3DSurface_LoadLocation() does not check if the rectangle specifies
1737 * the full surface. Most callers don't need that, so do it here. */
1738 if (pRect && pRect->top == 0 && pRect->left == 0
1739 && pRect->right == This->currentDesc.Width
1740 && pRect->bottom == This->currentDesc.Height)
1741 {
1742 pass_rect = NULL;
1743 }
1744
1745 if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
1746 && ((This->Flags & SFLAG_SWAPCHAIN) || iface == myDevice->render_targets[0])))
1747 {
1748 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pass_rect);
1749 }
1750
1751lock_end:
1752 if (This->Flags & SFLAG_PBO)
1753 {
1754 const struct wined3d_gl_info *gl_info;
1755 struct wined3d_context *context;
1756
1757 context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
1758 gl_info = context->gl_info;
1759
1760 ENTER_GL();
1761 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1762 checkGLcall("glBindBufferARB");
1763
1764 /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
1765 if(This->resource.allocatedMemory) {
1766 ERR("The surface already has PBO memory allocated!\n");
1767 }
1768
1769 This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1770 checkGLcall("glMapBufferARB");
1771
1772 /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
1773 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1774 checkGLcall("glBindBufferARB");
1775
1776 LEAVE_GL();
1777 context_release(context);
1778 }
1779
1780 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
1781 /* Don't dirtify */
1782 } else {
1783 IWineD3DBaseTexture *pBaseTexture;
1784 /**
1785 * Dirtify on lock
1786 * as seen in msdn docs
1787 */
1788 surface_add_dirty_rect(iface, pRect);
1789
1790 /** Dirtify Container if needed */
1791 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture))) {
1792 TRACE("Making container dirty\n");
1793 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
1794 IWineD3DBaseTexture_Release(pBaseTexture);
1795 } else {
1796 TRACE("Surface is standalone, no need to dirty the container\n");
1797 }
1798 }
1799
1800 return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
1801}
1802
1803static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
1804 GLint prev_store;
1805 GLint prev_rasterpos[4];
1806 GLint skipBytes = 0;
1807 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
1808 IWineD3DDeviceImpl *myDevice = This->resource.device;
1809 const struct wined3d_gl_info *gl_info;
1810 struct wined3d_context *context;
1811
1812 /* Activate the correct context for the render target */
1813 context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1814 gl_info = context->gl_info;
1815
1816 ENTER_GL();
1817
1818 if (!surface_is_offscreen((IWineD3DSurface *)This))
1819 {
1820 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1821 TRACE("Unlocking %#x buffer.\n", buffer);
1822 context_set_draw_buffer(context, buffer);
1823 }
1824 else
1825 {
1826 /* Primary offscreen render target */
1827 TRACE("Offscreen render target.\n");
1828 context_set_draw_buffer(context, myDevice->offscreenBuffer);
1829 }
1830
1831 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
1832 checkGLcall("glGetIntegerv");
1833 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
1834 checkGLcall("glGetIntegerv");
1835 glPixelZoom(1.0f, -1.0f);
1836 checkGLcall("glPixelZoom");
1837
1838 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1839 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
1840 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
1841
1842 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
1843 checkGLcall("glRasterPos3i");
1844
1845 /* Some drivers(radeon dri, others?) don't like exceptions during
1846 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1847 * after ReleaseDC. Reading it will cause an exception, which x11drv will
1848 * catch to put the dib section in InSync mode, which leads to a crash
1849 * and a blocked x server on my radeon card.
1850 *
1851 * The following lines read the dib section so it is put in InSync mode
1852 * before glDrawPixels is called and the crash is prevented. There won't
1853 * be any interfering gdi accesses, because UnlockRect is called from
1854 * ReleaseDC, and the app won't use the dc any more afterwards.
1855 */
1856 if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
1857 volatile BYTE read;
1858 read = This->resource.allocatedMemory[0];
1859 }
1860
1861 if(This->Flags & SFLAG_PBO) {
1862 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1863 checkGLcall("glBindBufferARB");
1864 }
1865
1866 /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
1867 if(This->Flags & SFLAG_LOCKED) {
1868 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1869 (This->lockedRect.bottom - This->lockedRect.top)-1,
1870 fmt, type,
1871 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1872 checkGLcall("glDrawPixels");
1873 } else {
1874 glDrawPixels(This->currentDesc.Width,
1875 This->currentDesc.Height,
1876 fmt, type, mem);
1877 checkGLcall("glDrawPixels");
1878 }
1879
1880 if(This->Flags & SFLAG_PBO) {
1881 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1882 checkGLcall("glBindBufferARB");
1883 }
1884
1885 glPixelZoom(1.0f, 1.0f);
1886 checkGLcall("glPixelZoom");
1887
1888 glRasterPos3iv(&prev_rasterpos[0]);
1889 checkGLcall("glRasterPos3iv");
1890
1891 /* Reset to previous pack row length */
1892 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1893 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
1894
1895 LEAVE_GL();
1896 context_release(context);
1897}
1898
1899static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1900 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1901 IWineD3DDeviceImpl *myDevice = This->resource.device;
1902 BOOL fullsurface;
1903
1904 if (!(This->Flags & SFLAG_LOCKED)) {
1905 WARN("trying to Unlock an unlocked surf@%p\n", This);
1906 return WINEDDERR_NOTLOCKED;
1907 }
1908
1909 if (This->Flags & SFLAG_PBO)
1910 {
1911 const struct wined3d_gl_info *gl_info;
1912 struct wined3d_context *context;
1913
1914 TRACE("Freeing PBO memory\n");
1915
1916 context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
1917 gl_info = context->gl_info;
1918
1919 ENTER_GL();
1920 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1921 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1922 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1923 checkGLcall("glUnmapBufferARB");
1924 LEAVE_GL();
1925 context_release(context);
1926
1927 This->resource.allocatedMemory = NULL;
1928 }
1929
1930 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1931
1932 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1933 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1934 goto unlock_end;
1935 }
1936
1937 if ((This->Flags & SFLAG_SWAPCHAIN) || (myDevice->render_targets && iface == myDevice->render_targets[0]))
1938 {
1939 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1940 static BOOL warned = FALSE;
1941 if(!warned) {
1942 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1943 warned = TRUE;
1944 }
1945 goto unlock_end;
1946 }
1947
1948 if(This->dirtyRect.left == 0 &&
1949 This->dirtyRect.top == 0 &&
1950 This->dirtyRect.right == This->currentDesc.Width &&
1951 This->dirtyRect.bottom == This->currentDesc.Height) {
1952 fullsurface = TRUE;
1953 } else {
1954 /* TODO: Proper partial rectangle tracking */
1955 fullsurface = FALSE;
1956 This->Flags |= SFLAG_INSYSMEM;
1957 }
1958
1959 switch(wined3d_settings.rendertargetlock_mode) {
1960 case RTL_READTEX:
1961 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
1962 /* drop through */
1963
1964 case RTL_READDRAW:
1965 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
1966 break;
1967 }
1968
1969 if(!fullsurface) {
1970 /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1971 * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1972 * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1973 * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1974 * not fully up to date because only a subrectangle was read in LockRect.
1975 */
1976 This->Flags &= ~SFLAG_INSYSMEM;
1977 This->Flags |= SFLAG_INDRAWABLE;
1978 }
1979
1980 This->dirtyRect.left = This->currentDesc.Width;
1981 This->dirtyRect.top = This->currentDesc.Height;
1982 This->dirtyRect.right = 0;
1983 This->dirtyRect.bottom = 0;
1984 } else if(iface == myDevice->stencilBufferTarget) {
1985 FIXME("Depth Stencil buffer locking is not implemented\n");
1986 } else {
1987 /* The rest should be a normal texture */
1988 IWineD3DBaseTextureImpl *impl;
1989 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1990 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1991 * states need resetting
1992 */
1993 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1994 if(impl->baseTexture.bindCount) {
1995 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1996 }
1997 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1998 }
1999 }
2000
2001 unlock_end:
2002 This->Flags &= ~SFLAG_LOCKED;
2003 memset(&This->lockedRect, 0, sizeof(RECT));
2004
2005 /* Overlays have to be redrawn manually after changes with the GL implementation */
2006 if(This->overlay_dest) {
2007 IWineD3DSurface_DrawOverlay(iface);
2008 }
2009 return WINED3D_OK;
2010}
2011
2012static void surface_release_client_storage(IWineD3DSurface *iface)
2013{
2014 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2015 struct wined3d_context *context;
2016
2017 context = context_acquire(This->resource.device, NULL, CTXUSAGE_RESOURCELOAD);
2018
2019 ENTER_GL();
2020 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2021#ifdef VBOXWDDM
2022 if (!VBOXSHRC_IS_SHARED_OPENED(This))
2023#endif
2024 {
2025 if(This->texture_name)
2026 {
2027 surface_bind_and_dirtify(This, FALSE);
2028 glTexImage2D(This->texture_target, This->texture_level,
2029 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
2030 }
2031 if(This->texture_name_srgb)
2032 {
2033 surface_bind_and_dirtify(This, TRUE);
2034 glTexImage2D(This->texture_target, This->texture_level,
2035 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
2036 }
2037 }
2038 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2039
2040 LEAVE_GL();
2041 context_release(context);
2042
2043 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
2044 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
2045 surface_force_reload(iface);
2046}
2047
2048static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
2049{
2050 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2051 WINED3DLOCKED_RECT lock;
2052 HRESULT hr;
2053 RGBQUAD col[256];
2054
2055 TRACE("(%p)->(%p)\n",This,pHDC);
2056
2057 if(This->Flags & SFLAG_USERPTR) {
2058 ERR("Not supported on surfaces with an application-provided surfaces\n");
2059 return WINEDDERR_NODC;
2060 }
2061
2062 /* Give more detailed info for ddraw */
2063 if (This->Flags & SFLAG_DCINUSE)
2064 return WINEDDERR_DCALREADYCREATED;
2065
2066 /* Can't GetDC if the surface is locked */
2067 if (This->Flags & SFLAG_LOCKED)
2068 return WINED3DERR_INVALIDCALL;
2069
2070 memset(&lock, 0, sizeof(lock)); /* To be sure */
2071
2072 /* Create a DIB section if there isn't a hdc yet */
2073 if(!This->hDC) {
2074 if(This->Flags & SFLAG_CLIENT) {
2075 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2076 surface_release_client_storage(iface);
2077 }
2078 hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
2079 if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
2080
2081 /* Use the dib section from now on if we are not using a PBO */
2082 if(!(This->Flags & SFLAG_PBO))
2083 This->resource.allocatedMemory = This->dib.bitmap_data;
2084 }
2085
2086 /* Lock the surface */
2087 hr = IWineD3DSurface_LockRect(iface,
2088 &lock,
2089 NULL,
2090 0);
2091
2092 if(This->Flags & SFLAG_PBO) {
2093 /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
2094 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
2095 }
2096
2097 if(FAILED(hr)) {
2098 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
2099 /* keep the dib section */
2100 return hr;
2101 }
2102
2103 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
2104 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
2105 {
2106 /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
2107 D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
2108 unsigned int n;
2109 const PALETTEENTRY *pal = NULL;
2110
2111 if(This->palette) {
2112 pal = This->palette->palents;
2113 } else {
2114 IWineD3DSurfaceImpl *dds_primary;
2115 IWineD3DSwapChainImpl *swapchain;
2116 swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
2117 dds_primary = (IWineD3DSurfaceImpl *)swapchain->frontBuffer;
2118 if (dds_primary && dds_primary->palette)
2119 pal = dds_primary->palette->palents;
2120 }
2121
2122 if (pal) {
2123 for (n=0; n<256; n++) {
2124 col[n].rgbRed = pal[n].peRed;
2125 col[n].rgbGreen = pal[n].peGreen;
2126 col[n].rgbBlue = pal[n].peBlue;
2127 col[n].rgbReserved = 0;
2128 }
2129 SetDIBColorTable(This->hDC, 0, 256, col);
2130 }
2131 }
2132
2133 *pHDC = This->hDC;
2134 TRACE("returning %p\n",*pHDC);
2135 This->Flags |= SFLAG_DCINUSE;
2136
2137 return WINED3D_OK;
2138}
2139
2140static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
2141{
2142 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2143
2144 TRACE("(%p)->(%p)\n",This,hDC);
2145
2146 if (!(This->Flags & SFLAG_DCINUSE))
2147 return WINEDDERR_NODC;
2148
2149 if (This->hDC !=hDC) {
2150 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
2151 return WINEDDERR_NODC;
2152 }
2153
2154 if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
2155 /* Copy the contents of the DIB over to the PBO */
2156 memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
2157 }
2158
2159 /* we locked first, so unlock now */
2160 IWineD3DSurface_UnlockRect(iface);
2161
2162 This->Flags &= ~SFLAG_DCINUSE;
2163
2164 return WINED3D_OK;
2165}
2166
2167/* ******************************************************
2168 IWineD3DSurface Internal (No mapping to directx api) parts follow
2169 ****************************************************** */
2170
2171HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, struct wined3d_format_desc *desc, CONVERT_TYPES *convert)
2172{
2173 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
2174 IWineD3DDeviceImpl *device = This->resource.device;
2175 BOOL blit_supported = FALSE;
2176 RECT rect = {0, 0, This->pow2Width, This->pow2Height};
2177
2178 /* Copy the default values from the surface. Below we might perform fixups */
2179 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2180 *desc = *This->resource.format_desc;
2181 *convert = NO_CONVERSION;
2182
2183 /* Ok, now look if we have to do any conversion */
2184 switch(This->resource.format_desc->format)
2185 {
2186 case WINED3DFMT_P8_UINT:
2187 /* ****************
2188 Paletted Texture
2189 **************** */
2190
2191 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
2192 &rect, This->resource.usage, This->resource.pool,
2193 This->resource.format_desc, &rect, This->resource.usage,
2194 This->resource.pool, This->resource.format_desc);
2195
2196 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2197 * texturing. Further also use conversion in case of color keying.
2198 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2199 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2200 * conflicts with this.
2201 */
2202 if (!((blit_supported && device->render_targets && This == (IWineD3DSurfaceImpl*)device->render_targets[0]))
2203 || colorkey_active || !use_texturing)
2204 {
2205 desc->glFormat = GL_RGBA;
2206 desc->glInternal = GL_RGBA;
2207 desc->glType = GL_UNSIGNED_BYTE;
2208 desc->conv_byte_count = 4;
2209 if(colorkey_active) {
2210 *convert = CONVERT_PALETTED_CK;
2211 } else {
2212 *convert = CONVERT_PALETTED;
2213 }
2214 }
2215 break;
2216
2217 case WINED3DFMT_B2G3R3_UNORM:
2218 /* **********************
2219 GL_UNSIGNED_BYTE_3_3_2
2220 ********************** */
2221 if (colorkey_active) {
2222 /* This texture format will never be used.. So do not care about color keying
2223 up until the point in time it will be needed :-) */
2224 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2225 }
2226 break;
2227
2228 case WINED3DFMT_B5G6R5_UNORM:
2229 if (colorkey_active) {
2230 *convert = CONVERT_CK_565;
2231 desc->glFormat = GL_RGBA;
2232 desc->glInternal = GL_RGB5_A1;
2233 desc->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2234 desc->conv_byte_count = 2;
2235 }
2236 break;
2237
2238 case WINED3DFMT_B5G5R5X1_UNORM:
2239 if (colorkey_active) {
2240 *convert = CONVERT_CK_5551;
2241 desc->glFormat = GL_BGRA;
2242 desc->glInternal = GL_RGB5_A1;
2243 desc->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2244 desc->conv_byte_count = 2;
2245 }
2246 break;
2247
2248 case WINED3DFMT_B8G8R8_UNORM:
2249 if (colorkey_active) {
2250 *convert = CONVERT_CK_RGB24;
2251 desc->glFormat = GL_RGBA;
2252 desc->glInternal = GL_RGBA8;
2253 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2254 desc->conv_byte_count = 4;
2255 }
2256 break;
2257
2258 case WINED3DFMT_B8G8R8X8_UNORM:
2259 if (colorkey_active) {
2260 *convert = CONVERT_RGB32_888;
2261 desc->glFormat = GL_RGBA;
2262 desc->glInternal = GL_RGBA8;
2263 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2264 desc->conv_byte_count = 4;
2265 }
2266 break;
2267
2268 default:
2269 break;
2270 }
2271
2272 return WINED3D_OK;
2273}
2274
2275void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
2276{
2277 IWineD3DDeviceImpl *device = This->resource.device;
2278 IWineD3DPaletteImpl *pal = This->palette;
2279 BOOL index_in_alpha = FALSE;
2280 unsigned int i;
2281
2282 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2283 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2284 * is slow. Further RGB->P8 conversion is not possible because palettes can have
2285 * duplicate entries. Store the color key in the unused alpha component to speed the
2286 * download up and to make conversion unneeded. */
2287 index_in_alpha = primary_render_target_is_p8(device);
2288
2289 if (!pal)
2290 {
2291 UINT dxVersion = ((IWineD3DImpl *)device->wined3d)->dxVersion;
2292
2293 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2294 if (dxVersion <= 7)
2295 {
2296 ERR("This code should never get entered for DirectDraw!, expect problems\n");
2297 if (index_in_alpha)
2298 {
2299 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2300 * there's no palette at this time. */
2301 for (i = 0; i < 256; i++) table[i][3] = i;
2302 }
2303 }
2304 else
2305 {
2306 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2307 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2308 * capability flag is present (wine does advertise this capability) */
2309 for (i = 0; i < 256; ++i)
2310 {
2311 table[i][0] = device->palettes[device->currentPalette][i].peRed;
2312 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
2313 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
2314 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
2315 }
2316 }
2317 }
2318 else
2319 {
2320 TRACE("Using surface palette %p\n", pal);
2321 /* Get the surface's palette */
2322 for (i = 0; i < 256; ++i)
2323 {
2324 table[i][0] = pal->palents[i].peRed;
2325 table[i][1] = pal->palents[i].peGreen;
2326 table[i][2] = pal->palents[i].peBlue;
2327
2328 /* When index_in_alpha is set the palette index is stored in the
2329 * alpha component. In case of a readback we can then read
2330 * GL_ALPHA. Color keying is handled in BltOverride using a
2331 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2332 * color key itself is passed to glAlphaFunc in other cases the
2333 * alpha component of pixels that should be masked away is set to 0. */
2334 if (index_in_alpha)
2335 {
2336 table[i][3] = i;
2337 }
2338 else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
2339 && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
2340 {
2341 table[i][3] = 0x00;
2342 }
2343 else if(pal->Flags & WINEDDPCAPS_ALPHA)
2344 {
2345 table[i][3] = pal->palents[i].peFlags;
2346 }
2347 else
2348 {
2349 table[i][3] = 0xFF;
2350 }
2351 }
2352 }
2353}
2354
2355static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
2356 UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
2357{
2358 const BYTE *source;
2359 BYTE *dest;
2360 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
2361
2362 switch (convert) {
2363 case NO_CONVERSION:
2364 {
2365 memcpy(dst, src, pitch * height);
2366 break;
2367 }
2368 case CONVERT_PALETTED:
2369 case CONVERT_PALETTED_CK:
2370 {
2371 IWineD3DPaletteImpl* pal = This->palette;
2372 BYTE table[256][4];
2373 unsigned int x, y;
2374
2375 if( pal == NULL) {
2376 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2377 }
2378
2379 d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2380
2381 for (y = 0; y < height; y++)
2382 {
2383 source = src + pitch * y;
2384 dest = dst + outpitch * y;
2385 /* This is an 1 bpp format, using the width here is fine */
2386 for (x = 0; x < width; x++) {
2387 BYTE color = *source++;
2388 *dest++ = table[color][0];
2389 *dest++ = table[color][1];
2390 *dest++ = table[color][2];
2391 *dest++ = table[color][3];
2392 }
2393 }
2394 }
2395 break;
2396
2397 case CONVERT_CK_565:
2398 {
2399 /* Converting the 565 format in 5551 packed to emulate color-keying.
2400
2401 Note : in all these conversion, it would be best to average the averaging
2402 pixels to get the color of the pixel that will be color-keyed to
2403 prevent 'color bleeding'. This will be done later on if ever it is
2404 too visible.
2405
2406 Note2: Nvidia documents say that their driver does not support alpha + color keying
2407 on the same surface and disables color keying in such a case
2408 */
2409 unsigned int x, y;
2410 const WORD *Source;
2411 WORD *Dest;
2412
2413 TRACE("Color keyed 565\n");
2414
2415 for (y = 0; y < height; y++) {
2416 Source = (const WORD *)(src + y * pitch);
2417 Dest = (WORD *) (dst + y * outpitch);
2418 for (x = 0; x < width; x++ ) {
2419 WORD color = *Source++;
2420 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
2421 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2422 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2423 *Dest |= 0x0001;
2424 }
2425 Dest++;
2426 }
2427 }
2428 }
2429 break;
2430
2431 case CONVERT_CK_5551:
2432 {
2433 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2434 unsigned int x, y;
2435 const WORD *Source;
2436 WORD *Dest;
2437 TRACE("Color keyed 5551\n");
2438 for (y = 0; y < height; y++) {
2439 Source = (const WORD *)(src + y * pitch);
2440 Dest = (WORD *) (dst + y * outpitch);
2441 for (x = 0; x < width; x++ ) {
2442 WORD color = *Source++;
2443 *Dest = color;
2444 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2445 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2446 *Dest |= (1 << 15);
2447 }
2448 else {
2449 *Dest &= ~(1 << 15);
2450 }
2451 Dest++;
2452 }
2453 }
2454 }
2455 break;
2456
2457 case CONVERT_CK_RGB24:
2458 {
2459 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2460 unsigned int x, y;
2461 for (y = 0; y < height; y++)
2462 {
2463 source = src + pitch * y;
2464 dest = dst + outpitch * y;
2465 for (x = 0; x < width; x++) {
2466 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
2467 DWORD dstcolor = color << 8;
2468 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2469 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2470 dstcolor |= 0xff;
2471 }
2472 *(DWORD*)dest = dstcolor;
2473 source += 3;
2474 dest += 4;
2475 }
2476 }
2477 }
2478 break;
2479
2480 case CONVERT_RGB32_888:
2481 {
2482 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2483 unsigned int x, y;
2484 for (y = 0; y < height; y++)
2485 {
2486 source = src + pitch * y;
2487 dest = dst + outpitch * y;
2488 for (x = 0; x < width; x++) {
2489 DWORD color = 0xffffff & *(const DWORD*)source;
2490 DWORD dstcolor = color << 8;
2491 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2492 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2493 dstcolor |= 0xff;
2494 }
2495 *(DWORD*)dest = dstcolor;
2496 source += 4;
2497 dest += 4;
2498 }
2499 }
2500 }
2501 break;
2502
2503 default:
2504 ERR("Unsupported conversion type %#x.\n", convert);
2505 }
2506 return WINED3D_OK;
2507}
2508
2509BOOL palette9_changed(IWineD3DSurfaceImpl *This)
2510{
2511 IWineD3DDeviceImpl *device = This->resource.device;
2512
2513 if (This->palette || (This->resource.format_desc->format != WINED3DFMT_P8_UINT
2514 && This->resource.format_desc->format != WINED3DFMT_P8_UINT_A8_UNORM))
2515 {
2516 /* If a ddraw-style palette is attached assume no d3d9 palette change.
2517 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2518 */
2519 return FALSE;
2520 }
2521
2522 if (This->palette9)
2523 {
2524 if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
2525 {
2526 return FALSE;
2527 }
2528 } else {
2529 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2530 }
2531 memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2532 return TRUE;
2533}
2534
2535static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2536 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2537 DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2538
2539 if (!(This->Flags & flag)) {
2540 TRACE("Reloading because surface is dirty\n");
2541 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2542 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2543 /* Reload: vice versa OR */
2544 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2545 /* Also reload: Color key is active AND the color key has changed */
2546 ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2547 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2548 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2549 TRACE("Reloading because of color keying\n");
2550 /* To perform the color key conversion we need a sysmem copy of
2551 * the surface. Make sure we have it
2552 */
2553
2554 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2555 /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2556 /* TODO: This is not necessarily needed with hw palettized texture support */
2557 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2558 } else {
2559 TRACE("surface is already in texture\n");
2560 return WINED3D_OK;
2561 }
2562
2563 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2564 * These resources are not bound by device size or format restrictions. Because of this,
2565 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2566 * However, these resources can always be created, locked, and copied.
2567 */
2568 if (This->resource.pool == WINED3DPOOL_SCRATCH )
2569 {
2570 FIXME("(%p) Operation not supported for scratch textures\n",This);
2571 return WINED3DERR_INVALIDCALL;
2572 }
2573
2574 IWineD3DSurface_LoadLocation(iface, flag, NULL /* no partial locking for textures yet */);
2575
2576#if 0
2577 {
2578 static unsigned int gen = 0;
2579 char buffer[4096];
2580 ++gen;
2581 if ((gen % 10) == 0) {
2582 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm",
2583 This, This->texture_target, This->texture_level, gen);
2584 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2585 }
2586 /*
2587 * debugging crash code
2588 if (gen == 250) {
2589 void** test = NULL;
2590 *test = 0;
2591 }
2592 */
2593 }
2594#endif
2595
2596 if (!(This->Flags & SFLAG_DONOTFREE)) {
2597 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2598 This->resource.allocatedMemory = NULL;
2599 This->resource.heapMemory = NULL;
2600 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE);
2601 }
2602
2603 return WINED3D_OK;
2604}
2605
2606/* Context activation is done by the caller. */
2607static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
2608 /* TODO: check for locks */
2609 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2610 IWineD3DBaseTexture *baseTexture = NULL;
2611
2612 TRACE("(%p)Checking to see if the container is a base texture\n", This);
2613 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2614 TRACE("Passing to container\n");
2615 IWineD3DBaseTexture_BindTexture(baseTexture, srgb);
2616 IWineD3DBaseTexture_Release(baseTexture);
2617 }
2618 else
2619 {
2620 GLuint *name;
2621
2622 TRACE("(%p) : Binding surface\n", This);
2623
2624 name = srgb ? &This->texture_name_srgb : &This->texture_name;
2625
2626 ENTER_GL();
2627
2628 if (!This->texture_level)
2629 {
2630 if (!*name) {
2631#ifdef VBOXWDDM
2632 if (VBOXSHRC_IS_SHARED_OPENED(This))
2633 {
2634 *name = VBOXSHRC_GET_SHAREHANDLE(This);
2635 }
2636 else
2637#endif
2638 {
2639 glGenTextures(1, name);
2640#ifdef VBOXWDDM
2641 if (VBOXSHRC_IS_SHARED(This))
2642 {
2643 VBOXSHRC_SET_SHAREHANDLE(This, *name);
2644 }
2645#endif
2646 }
2647 checkGLcall("glGenTextures");
2648 TRACE("Surface %p given name %d\n", This, *name);
2649
2650 glBindTexture(This->texture_target, *name);
2651 checkGLcall("glBindTexture");
2652 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2653 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2654 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2655 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2656 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2657 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2658 glTexParameteri(This->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2659 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2660 glTexParameteri(This->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2661 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2662 }
2663 /* This is where we should be reducing the amount of GLMemoryUsed */
2664 } else if (*name) {
2665 /* Mipmap surfaces should have a base texture container */
2666 ERR("Mipmap surface has a glTexture bound to it!\n");
2667 }
2668
2669 glBindTexture(This->texture_target, *name);
2670 checkGLcall("glBindTexture");
2671
2672 LEAVE_GL();
2673 }
2674}
2675
2676#include <errno.h>
2677#include <stdio.h>
2678static HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename)
2679{
2680 FILE* f = NULL;
2681 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2682 char *allocatedMemory;
2683 const char *textureRow;
2684 IWineD3DSwapChain *swapChain = NULL;
2685 int width, height, i, y;
2686 GLuint tmpTexture = 0;
2687 DWORD color;
2688 /*FIXME:
2689 Textures may not be stored in ->allocatedgMemory and a GlTexture
2690 so we should lock the surface before saving a snapshot, or at least check that
2691 */
2692 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2693 by calling GetTexImage and in compressed form by calling
2694 GetCompressedTexImageARB. Queried compressed images can be saved and
2695 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2696 texture images do not need to be processed by the GL and should
2697 significantly improve texture loading performance relative to uncompressed
2698 images. */
2699
2700/* Setup the width and height to be the internal texture width and height. */
2701 width = This->pow2Width;
2702 height = This->pow2Height;
2703/* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2704 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2705
2706 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2707 /* if were not a real texture then read the back buffer into a real texture */
2708 /* we don't want to interfere with the back buffer so read the data into a temporary
2709 * texture and then save the data out of the temporary texture
2710 */
2711 GLint prevRead;
2712 ENTER_GL();
2713 TRACE("(%p) Reading render target into texture\n", This);
2714
2715 glGenTextures(1, &tmpTexture);
2716 glBindTexture(GL_TEXTURE_2D, tmpTexture);
2717
2718 glTexImage2D(GL_TEXTURE_2D,
2719 0,
2720 GL_RGBA,
2721 width,
2722 height,
2723 0/*border*/,
2724 GL_RGBA,
2725 GL_UNSIGNED_INT_8_8_8_8_REV,
2726 NULL);
2727
2728 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2729 checkGLcall("glGetIntegerv");
2730 glReadBuffer(swapChain ? GL_BACK : This->resource.device->offscreenBuffer);
2731 checkGLcall("glReadBuffer");
2732 glCopyTexImage2D(GL_TEXTURE_2D,
2733 0,
2734 GL_RGBA,
2735 0,
2736 0,
2737 width,
2738 height,
2739 0);
2740
2741 checkGLcall("glCopyTexImage2D");
2742 glReadBuffer(prevRead);
2743 LEAVE_GL();
2744
2745 } else { /* bind the real texture, and make sure it up to date */
2746 surface_internal_preload(iface, SRGB_RGB);
2747 surface_bind_and_dirtify(This, FALSE);
2748 }
2749 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2750 ENTER_GL();
2751 FIXME("Saving texture level %d width %d height %d\n", This->texture_level, width, height);
2752 glGetTexImage(GL_TEXTURE_2D, This->texture_level, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, allocatedMemory);
2753 checkGLcall("glGetTexImage");
2754 if (tmpTexture) {
2755 glBindTexture(GL_TEXTURE_2D, 0);
2756 glDeleteTextures(1, &tmpTexture);
2757 }
2758 LEAVE_GL();
2759
2760 f = fopen(filename, "w+");
2761 if (NULL == f) {
2762 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2763 return WINED3DERR_INVALIDCALL;
2764 }
2765/* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2766 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format_desc->format));
2767/* TGA header */
2768 fputc(0,f);
2769 fputc(0,f);
2770 fputc(2,f);
2771 fputc(0,f);
2772 fputc(0,f);
2773 fputc(0,f);
2774 fputc(0,f);
2775 fputc(0,f);
2776 fputc(0,f);
2777 fputc(0,f);
2778 fputc(0,f);
2779 fputc(0,f);
2780/* short width*/
2781 fwrite(&width,2,1,f);
2782/* short height */
2783 fwrite(&height,2,1,f);
2784/* format rgba */
2785 fputc(0x20,f);
2786 fputc(0x28,f);
2787/* raw data */
2788 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up */
2789 if(swapChain)
2790 textureRow = allocatedMemory + (width * (height - 1) *4);
2791 else
2792 textureRow = allocatedMemory;
2793 for (y = 0 ; y < height; y++) {
2794 for (i = 0; i < width; i++) {
2795 color = *((const DWORD*)textureRow);
2796 fputc((color >> 16) & 0xFF, f); /* B */
2797 fputc((color >> 8) & 0xFF, f); /* G */
2798 fputc((color >> 0) & 0xFF, f); /* R */
2799 fputc((color >> 24) & 0xFF, f); /* A */
2800 textureRow += 4;
2801 }
2802 /* take two rows of the pointer to the texture memory */
2803 if(swapChain)
2804 (textureRow-= width << 3);
2805
2806 }
2807 TRACE("Closing file\n");
2808 fclose(f);
2809
2810 if(swapChain) {
2811 IWineD3DSwapChain_Release(swapChain);
2812 }
2813 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2814 return WINED3D_OK;
2815}
2816
2817static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2818 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2819 HRESULT hr;
2820
2821 TRACE("(%p) : Calling base function first\n", This);
2822 hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
2823 if(SUCCEEDED(hr)) {
2824 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
2825 TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format_desc->glFormat,
2826 This->resource.format_desc->glInternal, This->resource.format_desc->glType);
2827 }
2828 return hr;
2829}
2830
2831static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2832 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2833
2834 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2835 WARN("Surface is locked or the HDC is in use\n");
2836 return WINED3DERR_INVALIDCALL;
2837 }
2838
2839 if(Mem && Mem != This->resource.allocatedMemory) {
2840 void *release = NULL;
2841
2842 /* Do I have to copy the old surface content? */
2843 if(This->Flags & SFLAG_DIBSECTION) {
2844 /* Release the DC. No need to hold the critical section for the update
2845 * Thread because this thread runs only on front buffers, but this method
2846 * fails for render targets in the check above.
2847 */
2848 SelectObject(This->hDC, This->dib.holdbitmap);
2849 DeleteDC(This->hDC);
2850 /* Release the DIB section */
2851 DeleteObject(This->dib.DIBsection);
2852 This->dib.bitmap_data = NULL;
2853 This->resource.allocatedMemory = NULL;
2854 This->hDC = NULL;
2855 This->Flags &= ~SFLAG_DIBSECTION;
2856 } else if(!(This->Flags & SFLAG_USERPTR)) {
2857 release = This->resource.heapMemory;
2858 This->resource.heapMemory = NULL;
2859 }
2860 This->resource.allocatedMemory = Mem;
2861 This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2862
2863 /* Now the surface memory is most up do date. Invalidate drawable and texture */
2864 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2865
2866 /* For client textures opengl has to be notified */
2867 if(This->Flags & SFLAG_CLIENT) {
2868 surface_release_client_storage(iface);
2869 }
2870
2871 /* Now free the old memory if any */
2872 HeapFree(GetProcessHeap(), 0, release);
2873 } else if(This->Flags & SFLAG_USERPTR) {
2874 /* LockRect and GetDC will re-create the dib section and allocated memory */
2875 This->resource.allocatedMemory = NULL;
2876 /* HeapMemory should be NULL already */
2877 if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
2878 This->Flags &= ~SFLAG_USERPTR;
2879
2880 if(This->Flags & SFLAG_CLIENT) {
2881 surface_release_client_storage(iface);
2882 }
2883 }
2884 return WINED3D_OK;
2885}
2886
2887void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
2888
2889 /* Flip the surface contents */
2890 /* Flip the DC */
2891 {
2892 HDC tmp;
2893 tmp = front->hDC;
2894 front->hDC = back->hDC;
2895 back->hDC = tmp;
2896 }
2897
2898 /* Flip the DIBsection */
2899 {
2900 HBITMAP tmp;
2901 BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
2902 tmp = front->dib.DIBsection;
2903 front->dib.DIBsection = back->dib.DIBsection;
2904 back->dib.DIBsection = tmp;
2905
2906 if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
2907 else front->Flags &= ~SFLAG_DIBSECTION;
2908 if(hasDib) back->Flags |= SFLAG_DIBSECTION;
2909 else back->Flags &= ~SFLAG_DIBSECTION;
2910 }
2911
2912 /* Flip the surface data */
2913 {
2914 void* tmp;
2915
2916 tmp = front->dib.bitmap_data;
2917 front->dib.bitmap_data = back->dib.bitmap_data;
2918 back->dib.bitmap_data = tmp;
2919
2920 tmp = front->resource.allocatedMemory;
2921 front->resource.allocatedMemory = back->resource.allocatedMemory;
2922 back->resource.allocatedMemory = tmp;
2923
2924 tmp = front->resource.heapMemory;
2925 front->resource.heapMemory = back->resource.heapMemory;
2926 back->resource.heapMemory = tmp;
2927 }
2928
2929 /* Flip the PBO */
2930 {
2931 GLuint tmp_pbo = front->pbo;
2932 front->pbo = back->pbo;
2933 back->pbo = tmp_pbo;
2934 }
2935
2936 /* client_memory should not be different, but just in case */
2937 {
2938 BOOL tmp;
2939 tmp = front->dib.client_memory;
2940 front->dib.client_memory = back->dib.client_memory;
2941 back->dib.client_memory = tmp;
2942 }
2943
2944 /* Flip the opengl texture */
2945 {
2946 GLuint tmp;
2947
2948 tmp = back->texture_name;
2949 back->texture_name = front->texture_name;
2950 front->texture_name = tmp;
2951
2952 tmp = back->texture_name_srgb;
2953 back->texture_name_srgb = front->texture_name_srgb;
2954 front->texture_name_srgb = tmp;
2955 }
2956
2957 {
2958 DWORD tmp_flags = back->Flags;
2959 back->Flags = front->Flags;
2960 front->Flags = tmp_flags;
2961 }
2962}
2963
2964static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2965 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2966 IWineD3DSwapChainImpl *swapchain = NULL;
2967 HRESULT hr;
2968 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2969
2970 /* Flipping is only supported on RenderTargets and overlays*/
2971 if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
2972 WARN("Tried to flip a non-render target, non-overlay surface\n");
2973 return WINEDDERR_NOTFLIPPABLE;
2974 }
2975
2976 if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
2977 flip_surface(This, (IWineD3DSurfaceImpl *) override);
2978
2979 /* Update the overlay if it is visible */
2980 if(This->overlay_dest) {
2981 return IWineD3DSurface_DrawOverlay((IWineD3DSurface *) This);
2982 } else {
2983 return WINED3D_OK;
2984 }
2985 }
2986
2987 if(override) {
2988 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2989 * FIXME("(%p) Target override is not supported by now\n", This);
2990 * Additionally, it isn't really possible to support triple-buffering
2991 * properly on opengl at all
2992 */
2993 }
2994
2995 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2996 if(!swapchain) {
2997 ERR("Flipped surface is not on a swapchain\n");
2998 return WINEDDERR_NOTFLIPPABLE;
2999 }
3000
3001 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
3002 * and only d3d8 and d3d9 apps specify the presentation interval
3003 */
3004 if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
3005 /* Most common case first to avoid wasting time on all the other cases */
3006 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
3007 } else if(Flags & WINEDDFLIP_NOVSYNC) {
3008 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3009 } else if(Flags & WINEDDFLIP_INTERVAL2) {
3010 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
3011 } else if(Flags & WINEDDFLIP_INTERVAL3) {
3012 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
3013 } else {
3014 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
3015 }
3016
3017 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
3018 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
3019 NULL, NULL, swapchain->win_handle, NULL, 0);
3020 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
3021 return hr;
3022}
3023
3024/* Does a direct frame buffer -> texture copy. Stretching is done
3025 * with single pixel copy calls
3026 */
3027static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3028 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
3029{
3030 IWineD3DDeviceImpl *myDevice = This->resource.device;
3031 float xrel, yrel;
3032 UINT row;
3033 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3034 struct wined3d_context *context;
3035 BOOL upsidedown = FALSE;
3036 RECT dst_rect = *dst_rect_in;
3037
3038 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3039 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3040 */
3041 if(dst_rect.top > dst_rect.bottom) {
3042 UINT tmp = dst_rect.bottom;
3043 dst_rect.bottom = dst_rect.top;
3044 dst_rect.top = tmp;
3045 upsidedown = TRUE;
3046 }
3047
3048 context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3049 surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3050 ENTER_GL();
3051
3052 /* Bind the target texture */
3053 glBindTexture(This->texture_target, This->texture_name);
3054 checkGLcall("glBindTexture");
3055 if(surface_is_offscreen(SrcSurface)) {
3056 TRACE("Reading from an offscreen target\n");
3057 upsidedown = !upsidedown;
3058 glReadBuffer(myDevice->offscreenBuffer);
3059 }
3060 else
3061 {
3062 glReadBuffer(surface_get_gl_buffer(SrcSurface));
3063 }
3064 checkGLcall("glReadBuffer");
3065
3066 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
3067 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
3068
3069 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3070 {
3071 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3072
3073 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
3074 ERR("Texture filtering not supported in direct blit\n");
3075 }
3076 }
3077 else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
3078 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3079 {
3080 ERR("Texture filtering not supported in direct blit\n");
3081 }
3082
3083 if (upsidedown
3084 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3085 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3086 {
3087 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
3088
3089 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3090 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3091 src_rect->left, Src->currentDesc.Height - src_rect->bottom,
3092 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3093 } else {
3094 UINT yoffset = Src->currentDesc.Height - src_rect->top + dst_rect.top - 1;
3095 /* I have to process this row by row to swap the image,
3096 * otherwise it would be upside down, so stretching in y direction
3097 * doesn't cost extra time
3098 *
3099 * However, stretching in x direction can be avoided if not necessary
3100 */
3101 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
3102 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3103 {
3104 /* Well, that stuff works, but it's very slow.
3105 * find a better way instead
3106 */
3107 UINT col;
3108
3109 for(col = dst_rect.left; col < dst_rect.right; col++) {
3110 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3111 dst_rect.left + col /* x offset */, row /* y offset */,
3112 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3113 }
3114 } else {
3115 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3116 dst_rect.left /* x offset */, row /* y offset */,
3117 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
3118 }
3119 }
3120 }
3121 checkGLcall("glCopyTexSubImage2D");
3122
3123 LEAVE_GL();
3124 context_release(context);
3125
3126 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3127 * path is never entered
3128 */
3129 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3130}
3131
3132/* Uses the hardware to stretch and flip the image */
3133static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3134 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
3135{
3136 IWineD3DDeviceImpl *myDevice = This->resource.device;
3137 GLuint src, backup = 0;
3138 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3139 IWineD3DSwapChainImpl *src_swapchain = NULL;
3140 float left, right, top, bottom; /* Texture coordinates */
3141 UINT fbwidth = Src->currentDesc.Width;
3142 UINT fbheight = Src->currentDesc.Height;
3143 struct wined3d_context *context;
3144 GLenum drawBuffer = GL_BACK;
3145 GLenum texture_target;
3146 BOOL noBackBufferBackup;
3147 BOOL src_offscreen;
3148 BOOL upsidedown = FALSE;
3149 RECT dst_rect = *dst_rect_in;
3150
3151 TRACE("Using hwstretch blit\n");
3152 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3153 context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3154 surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3155
3156 src_offscreen = surface_is_offscreen(SrcSurface);
3157 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3158 if (!noBackBufferBackup && !Src->texture_name)
3159 {
3160 /* Get it a description */
3161 surface_internal_preload(SrcSurface, SRGB_RGB);
3162 }
3163 ENTER_GL();
3164
3165 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3166 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3167 */
3168 if (context->aux_buffers >= 2)
3169 {
3170 /* Got more than one aux buffer? Use the 2nd aux buffer */
3171 drawBuffer = GL_AUX1;
3172 }
3173 else if ((!src_offscreen || myDevice->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3174 {
3175 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3176 drawBuffer = GL_AUX0;
3177 }
3178
3179 if(noBackBufferBackup) {
3180 glGenTextures(1, &backup);
3181 checkGLcall("glGenTextures");
3182 glBindTexture(GL_TEXTURE_2D, backup);
3183 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3184 texture_target = GL_TEXTURE_2D;
3185 } else {
3186 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3187 * we are reading from the back buffer, the backup can be used as source texture
3188 */
3189 texture_target = Src->texture_target;
3190 glBindTexture(texture_target, Src->texture_name);
3191 checkGLcall("glBindTexture(texture_target, Src->texture_name)");
3192 glEnable(texture_target);
3193 checkGLcall("glEnable(texture_target)");
3194
3195 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3196 Src->Flags &= ~SFLAG_INTEXTURE;
3197 }
3198
3199 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3200 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3201 */
3202 if(dst_rect.top > dst_rect.bottom) {
3203 UINT tmp = dst_rect.bottom;
3204 dst_rect.bottom = dst_rect.top;
3205 dst_rect.top = tmp;
3206 upsidedown = TRUE;
3207 }
3208
3209 if (src_offscreen)
3210 {
3211 TRACE("Reading from an offscreen target\n");
3212 upsidedown = !upsidedown;
3213 glReadBuffer(myDevice->offscreenBuffer);
3214 }
3215 else
3216 {
3217 glReadBuffer(surface_get_gl_buffer(SrcSurface));
3218 }
3219
3220 /* TODO: Only back up the part that will be overwritten */
3221 glCopyTexSubImage2D(texture_target, 0,
3222 0, 0 /* read offsets */,
3223 0, 0,
3224 fbwidth,
3225 fbheight);
3226
3227 checkGLcall("glCopyTexSubImage2D");
3228
3229 /* No issue with overriding these - the sampler is dirty due to blit usage */
3230 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3231 wined3d_gl_mag_filter(magLookup, Filter));
3232 checkGLcall("glTexParameteri");
3233 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3234 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
3235 checkGLcall("glTexParameteri");
3236
3237 IWineD3DSurface_GetContainer((IWineD3DSurface *)SrcSurface, &IID_IWineD3DSwapChain, (void **)&src_swapchain);
3238 if (src_swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)src_swapchain);
3239 if (!src_swapchain || (IWineD3DSurface *) Src == src_swapchain->backBuffer[0]) {
3240 src = backup ? backup : Src->texture_name;
3241 } else {
3242 glReadBuffer(GL_FRONT);
3243 checkGLcall("glReadBuffer(GL_FRONT)");
3244
3245 glGenTextures(1, &src);
3246 checkGLcall("glGenTextures(1, &src)");
3247 glBindTexture(GL_TEXTURE_2D, src);
3248 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3249
3250 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3251 * out for power of 2 sizes
3252 */
3253 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
3254 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3255 checkGLcall("glTexImage2D");
3256 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3257 0, 0 /* read offsets */,
3258 0, 0,
3259 fbwidth,
3260 fbheight);
3261
3262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3263 checkGLcall("glTexParameteri");
3264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3265 checkGLcall("glTexParameteri");
3266
3267 glReadBuffer(GL_BACK);
3268 checkGLcall("glReadBuffer(GL_BACK)");
3269
3270 if(texture_target != GL_TEXTURE_2D) {
3271 glDisable(texture_target);
3272 glEnable(GL_TEXTURE_2D);
3273 texture_target = GL_TEXTURE_2D;
3274 }
3275 }
3276 checkGLcall("glEnd and previous");
3277
3278 left = src_rect->left;
3279 right = src_rect->right;
3280
3281 if(upsidedown) {
3282 top = Src->currentDesc.Height - src_rect->top;
3283 bottom = Src->currentDesc.Height - src_rect->bottom;
3284 } else {
3285 top = Src->currentDesc.Height - src_rect->bottom;
3286 bottom = Src->currentDesc.Height - src_rect->top;
3287 }
3288
3289 if(Src->Flags & SFLAG_NORMCOORD) {
3290 left /= Src->pow2Width;
3291 right /= Src->pow2Width;
3292 top /= Src->pow2Height;
3293 bottom /= Src->pow2Height;
3294 }
3295
3296 /* draw the source texture stretched and upside down. The correct surface is bound already */
3297 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3298 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3299
3300 context_set_draw_buffer(context, drawBuffer);
3301 glReadBuffer(drawBuffer);
3302
3303 glBegin(GL_QUADS);
3304 /* bottom left */
3305 glTexCoord2f(left, bottom);
3306 glVertex2i(0, fbheight);
3307
3308 /* top left */
3309 glTexCoord2f(left, top);
3310 glVertex2i(0, fbheight - dst_rect.bottom - dst_rect.top);
3311
3312 /* top right */
3313 glTexCoord2f(right, top);
3314 glVertex2i(dst_rect.right - dst_rect.left, fbheight - dst_rect.bottom - dst_rect.top);
3315
3316 /* bottom right */
3317 glTexCoord2f(right, bottom);
3318 glVertex2i(dst_rect.right - dst_rect.left, fbheight);
3319 glEnd();
3320 checkGLcall("glEnd and previous");
3321
3322 if (texture_target != This->texture_target)
3323 {
3324 glDisable(texture_target);
3325 glEnable(This->texture_target);
3326 texture_target = This->texture_target;
3327 }
3328
3329 /* Now read the stretched and upside down image into the destination texture */
3330 glBindTexture(texture_target, This->texture_name);
3331 checkGLcall("glBindTexture");
3332 glCopyTexSubImage2D(texture_target,
3333 0,
3334 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3335 0, 0, /* We blitted the image to the origin */
3336 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3337 checkGLcall("glCopyTexSubImage2D");
3338
3339 if(drawBuffer == GL_BACK) {
3340 /* Write the back buffer backup back */
3341 if(backup) {
3342 if(texture_target != GL_TEXTURE_2D) {
3343 glDisable(texture_target);
3344 glEnable(GL_TEXTURE_2D);
3345 texture_target = GL_TEXTURE_2D;
3346 }
3347 glBindTexture(GL_TEXTURE_2D, backup);
3348 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3349 } else {
3350 if (texture_target != Src->texture_target)
3351 {
3352 glDisable(texture_target);
3353 glEnable(Src->texture_target);
3354 texture_target = Src->texture_target;
3355 }
3356 glBindTexture(Src->texture_target, Src->texture_name);
3357 checkGLcall("glBindTexture(Src->texture_target, Src->texture_name)");
3358 }
3359
3360 glBegin(GL_QUADS);
3361 /* top left */
3362 glTexCoord2f(0.0f, (float)fbheight / (float)Src->pow2Height);
3363 glVertex2i(0, 0);
3364
3365 /* bottom left */
3366 glTexCoord2f(0.0f, 0.0f);
3367 glVertex2i(0, fbheight);
3368
3369 /* bottom right */
3370 glTexCoord2f((float)fbwidth / (float)Src->pow2Width, 0.0f);
3371 glVertex2i(fbwidth, Src->currentDesc.Height);
3372
3373 /* top right */
3374 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
3375 glVertex2i(fbwidth, 0);
3376 glEnd();
3377 }
3378 glDisable(texture_target);
3379 checkGLcall("glDisable(texture_target)");
3380
3381 /* Cleanup */
3382 if (src != Src->texture_name && src != backup)
3383 {
3384 glDeleteTextures(1, &src);
3385 checkGLcall("glDeleteTextures(1, &src)");
3386 }
3387 if(backup) {
3388 glDeleteTextures(1, &backup);
3389 checkGLcall("glDeleteTextures(1, &backup)");
3390 }
3391
3392 LEAVE_GL();
3393
3394 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
3395
3396 context_release(context);
3397
3398 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3399 * path is never entered
3400 */
3401 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3402}
3403
3404/* Until the blit_shader is ready, define some prototypes here. */
3405static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
3406 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
3407 const struct wined3d_format_desc *src_format_desc,
3408 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
3409 const struct wined3d_format_desc *dst_format_desc);
3410
3411/* Not called from the VTable */
3412static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3413 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
3414 WINED3DTEXTUREFILTERTYPE Filter)
3415{
3416 IWineD3DDeviceImpl *myDevice = This->resource.device;
3417 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
3418 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3419 RECT dst_rect, src_rect;
3420
3421 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3422
3423 /* Get the swapchain. One of the surfaces has to be a primary surface */
3424 if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3425 WARN("Destination is in sysmem, rejecting gl blt\n");
3426 return WINED3DERR_INVALIDCALL;
3427 }
3428 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
3429 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
3430 if(Src) {
3431 if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3432 WARN("Src is in sysmem, rejecting gl blt\n");
3433 return WINED3DERR_INVALIDCALL;
3434 }
3435 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
3436 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
3437 }
3438
3439 /* Early sort out of cases where no render target is used */
3440 if(!dstSwapchain && !srcSwapchain &&
3441 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3442 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
3443 return WINED3DERR_INVALIDCALL;
3444 }
3445
3446 /* No destination color keying supported */
3447 if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
3448 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3449 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3450 return WINED3DERR_INVALIDCALL;
3451 }
3452
3453 surface_get_rect(This, DestRect, &dst_rect);
3454 if(Src) surface_get_rect(Src, SrcRect, &src_rect);
3455
3456 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3457 if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
3458 ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
3459 /* Half-life does a Blt from the back buffer to the front buffer,
3460 * Full surface size, no flags... Use present instead
3461 *
3462 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3463 */
3464
3465 /* Check rects - IWineD3DDevice_Present doesn't handle them */
3466 while(1)
3467 {
3468 TRACE("Looking if a Present can be done...\n");
3469 /* Source Rectangle must be full surface */
3470 if(src_rect.left != 0 || src_rect.top != 0 ||
3471 src_rect.right != Src->currentDesc.Width || src_rect.bottom != Src->currentDesc.Height) {
3472 TRACE("No, Source rectangle doesn't match\n");
3473 break;
3474 }
3475
3476 /* No stretching may occur */
3477 if(src_rect.right != dst_rect.right - dst_rect.left ||
3478 src_rect.bottom != dst_rect.bottom - dst_rect.top) {
3479 TRACE("No, stretching is done\n");
3480 break;
3481 }
3482
3483 /* Destination must be full surface or match the clipping rectangle */
3484 if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
3485 {
3486 RECT cliprect;
3487 POINT pos[2];
3488 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
3489 pos[0].x = dst_rect.left;
3490 pos[0].y = dst_rect.top;
3491 pos[1].x = dst_rect.right;
3492 pos[1].y = dst_rect.bottom;
3493 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
3494 pos, 2);
3495
3496 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
3497 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
3498 {
3499 TRACE("No, dest rectangle doesn't match(clipper)\n");
3500 TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
3501 TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
3502 break;
3503 }
3504 }
3505 else
3506 {
3507 if(dst_rect.left != 0 || dst_rect.top != 0 ||
3508 dst_rect.right != This->currentDesc.Width || dst_rect.bottom != This->currentDesc.Height) {
3509 TRACE("No, dest rectangle doesn't match(surface size)\n");
3510 break;
3511 }
3512 }
3513
3514 TRACE("Yes\n");
3515
3516 /* These flags are unimportant for the flag check, remove them */
3517 if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
3518 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
3519
3520 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3521 * take very long, while a flip is fast.
3522 * This applies to Half-Life, which does such Blts every time it finished
3523 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3524 * menu. This is also used by all apps when they do windowed rendering
3525 *
3526 * The problem is that flipping is not really the same as copying. After a
3527 * Blt the front buffer is a copy of the back buffer, and the back buffer is
3528 * untouched. Therefore it's necessary to override the swap effect
3529 * and to set it back after the flip.
3530 *
3531 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3532 * testcases.
3533 */
3534
3535 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
3536 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3537
3538 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3539 IWineD3DSwapChain_Present((IWineD3DSwapChain *)dstSwapchain,
3540 NULL, NULL, dstSwapchain->win_handle, NULL, 0);
3541
3542 dstSwapchain->presentParms.SwapEffect = orig_swap;
3543
3544 return WINED3D_OK;
3545 }
3546 break;
3547 }
3548
3549 TRACE("Unsupported blit between buffers on the same swapchain\n");
3550 return WINED3DERR_INVALIDCALL;
3551 } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
3552 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3553 return WINED3DERR_INVALIDCALL;
3554 } else if(dstSwapchain && srcSwapchain) {
3555 FIXME("Implement hardware blit between two different swapchains\n");
3556 return WINED3DERR_INVALIDCALL;
3557 } else if(dstSwapchain) {
3558 if(SrcSurface == myDevice->render_targets[0]) {
3559 TRACE("Blit from active render target to a swapchain\n");
3560 /* Handled with regular texture -> swapchain blit */
3561 }
3562 } else if(srcSwapchain && This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3563 FIXME("Implement blit from a swapchain to the active render target\n");
3564 return WINED3DERR_INVALIDCALL;
3565 }
3566
3567 if((srcSwapchain || SrcSurface == myDevice->render_targets[0]) && !dstSwapchain) {
3568 /* Blit from render target to texture */
3569 BOOL stretchx;
3570
3571 /* P8 read back is not implemented */
3572 if (Src->resource.format_desc->format == WINED3DFMT_P8_UINT ||
3573 This->resource.format_desc->format == WINED3DFMT_P8_UINT)
3574 {
3575 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3576 return WINED3DERR_INVALIDCALL;
3577 }
3578
3579 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3580 TRACE("Color keying not supported by frame buffer to texture blit\n");
3581 return WINED3DERR_INVALIDCALL;
3582 /* Destination color key is checked above */
3583 }
3584
3585 if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
3586 stretchx = TRUE;
3587 } else {
3588 stretchx = FALSE;
3589 }
3590
3591 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3592 * flip the image nor scale it.
3593 *
3594 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3595 * -> If the app wants a image width an unscaled width, copy it line per line
3596 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3597 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3598 * back buffer. This is slower than reading line per line, thus not used for flipping
3599 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3600 * pixel by pixel
3601 *
3602 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3603 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3604 * backends.
3605 */
3606 if (fbo_blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3607 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3608 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3609 {
3610 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &src_rect,
3611 (IWineD3DSurface *)This, &dst_rect, Filter);
3612 } else if((!stretchx) || dst_rect.right - dst_rect.left > Src->currentDesc.Width ||
3613 dst_rect.bottom - dst_rect.top > Src->currentDesc.Height) {
3614 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3615 fb_copy_to_texture_direct(This, SrcSurface, &src_rect, &dst_rect, Filter);
3616 } else {
3617 TRACE("Using hardware stretching to flip / stretch the texture\n");
3618 fb_copy_to_texture_hwstretch(This, SrcSurface, &src_rect, &dst_rect, Filter);
3619 }
3620
3621 if(!(This->Flags & SFLAG_DONOTFREE)) {
3622 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3623 This->resource.allocatedMemory = NULL;
3624 This->resource.heapMemory = NULL;
3625 } else {
3626 This->Flags &= ~SFLAG_INSYSMEM;
3627 }
3628
3629 return WINED3D_OK;
3630 } else if(Src) {
3631 /* Blit from offscreen surface to render target */
3632 DWORD oldCKeyFlags = Src->CKeyFlags;
3633 WINEDDCOLORKEY oldBltCKey = Src->SrcBltCKey;
3634 struct wined3d_context *context;
3635
3636 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
3637
3638 if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3639 && fbo_blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3640 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3641 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3642 {
3643 TRACE("Using stretch_rect_fbo\n");
3644 /* The source is always a texture, but never the currently active render target, and the texture
3645 * contents are never upside down
3646 */
3647 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &src_rect,
3648 (IWineD3DSurface *)This, &dst_rect, Filter);
3649 return WINED3D_OK;
3650 }
3651
3652 if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3653 && arbfp_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3654 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3655 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3656 {
3657 return arbfp_blit_surface(myDevice, Src, &src_rect, This, &dst_rect, BLIT_OP_BLIT, Filter);
3658 }
3659
3660 /* Color keying: Check if we have to do a color keyed blt,
3661 * and if not check if a color key is activated.
3662 *
3663 * Just modify the color keying parameters in the surface and restore them afterwards
3664 * The surface keeps track of the color key last used to load the opengl surface.
3665 * PreLoad will catch the change to the flags and color key and reload if necessary.
3666 */
3667 if(Flags & WINEDDBLT_KEYSRC) {
3668 /* Use color key from surface */
3669 } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3670 /* Use color key from DDBltFx */
3671 Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
3672 Src->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3673 } else {
3674 /* Do not use color key */
3675 Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3676 }
3677
3678 /* Now load the surface */
3679 surface_internal_preload((IWineD3DSurface *) Src, SRGB_RGB);
3680
3681 /* Activate the destination context, set it up for blitting */
3682 context = context_acquire(myDevice, (IWineD3DSurface *)This, CTXUSAGE_BLIT);
3683
3684 /* The coordinates of the ddraw front buffer are always fullscreen ('screen coordinates',
3685 * while OpenGL coordinates are window relative.
3686 * Also beware of the origin difference(top left vs bottom left).
3687 * Also beware that the front buffer's surface size is screen width x screen height,
3688 * whereas the real gl drawable size is the size of the window.
3689 */
3690 if (dstSwapchain && (IWineD3DSurface *)This == dstSwapchain->frontBuffer) {
3691 RECT windowsize;
3692 POINT offset = {0,0};
3693 UINT h;
3694 ClientToScreen(context->win_handle, &offset);
3695 GetClientRect(context->win_handle, &windowsize);
3696 h = windowsize.bottom - windowsize.top;
3697 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
3698 dst_rect.top -= offset.y; dst_rect.bottom -=offset.y;
3699 dst_rect.top += This->currentDesc.Height - h; dst_rect.bottom += This->currentDesc.Height - h;
3700 }
3701
3702 if (!myDevice->blitter->blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3703 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3704 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3705 {
3706 FIXME("Unsupported blit operation falling back to software\n");
3707 return WINED3DERR_INVALIDCALL;
3708 }
3709
3710 myDevice->blitter->set_shader((IWineD3DDevice *) myDevice, Src);
3711
3712 ENTER_GL();
3713
3714 /* This is for color keying */
3715 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3716 glEnable(GL_ALPHA_TEST);
3717 checkGLcall("glEnable(GL_ALPHA_TEST)");
3718
3719 /* When the primary render target uses P8, the alpha component contains the palette index.
3720 * Which means that the colorkey is one of the palette entries. In other cases pixels that
3721 * should be masked away have alpha set to 0. */
3722 if(primary_render_target_is_p8(myDevice))
3723 glAlphaFunc(GL_NOTEQUAL, (float)Src->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
3724 else
3725 glAlphaFunc(GL_NOTEQUAL, 0.0f);
3726 checkGLcall("glAlphaFunc");
3727 } else {
3728 glDisable(GL_ALPHA_TEST);
3729 checkGLcall("glDisable(GL_ALPHA_TEST)");
3730 }
3731
3732 /* Draw a textured quad
3733 */
3734 draw_textured_quad(Src, &src_rect, &dst_rect, Filter);
3735
3736 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3737 glDisable(GL_ALPHA_TEST);
3738 checkGLcall("glDisable(GL_ALPHA_TEST)");
3739 }
3740
3741 /* Restore the color key parameters */
3742 Src->CKeyFlags = oldCKeyFlags;
3743 Src->SrcBltCKey = oldBltCKey;
3744
3745 LEAVE_GL();
3746
3747 /* Leave the opengl state valid for blitting */
3748 myDevice->blitter->unset_shader((IWineD3DDevice *) myDevice);
3749
3750 if (wined3d_settings.strict_draw_ordering || (dstSwapchain
3751 && ((IWineD3DSurface *)This == dstSwapchain->frontBuffer
3752 || dstSwapchain->num_contexts > 1)))
3753 wglFlush(); /* Flush to ensure ordering across contexts. */
3754
3755 context_release(context);
3756
3757 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3758 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3759 * is outdated now
3760 */
3761 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INDRAWABLE, TRUE);
3762
3763 return WINED3D_OK;
3764 } else {
3765 /* Source-Less Blit to render target */
3766 if (Flags & WINEDDBLT_COLORFILL) {
3767 DWORD color;
3768
3769 TRACE("Colorfill\n");
3770
3771 /* The color as given in the Blt function is in the format of the frame-buffer...
3772 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3773 */
3774 if (!surface_convert_color_to_argb(This, DDBltFx->u5.dwFillColor, &color))
3775 {
3776 /* The color conversion function already prints an error, so need to do it here */
3777 return WINED3DERR_INVALIDCALL;
3778 }
3779
3780 if (ffp_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_COLOR_FILL,
3781 NULL, 0, 0, NULL,
3782 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3783 {
3784 return ffp_blit.color_fill(myDevice, This, &dst_rect, color);
3785 }
3786 else if (cpu_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_COLOR_FILL,
3787 NULL, 0, 0, NULL,
3788 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3789 {
3790 return cpu_blit.color_fill(myDevice, This, &dst_rect, color);
3791 }
3792 return WINED3DERR_INVALIDCALL;
3793 }
3794 }
3795
3796 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3797 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3798 return WINED3DERR_INVALIDCALL;
3799}
3800
3801static HRESULT IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3802 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx)
3803{
3804 IWineD3DDeviceImpl *myDevice = This->resource.device;
3805 float depth;
3806
3807 if (Flags & WINEDDBLT_DEPTHFILL) {
3808 switch(This->resource.format_desc->format)
3809 {
3810 case WINED3DFMT_D16_UNORM:
3811 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
3812 break;
3813 case WINED3DFMT_S1_UINT_D15_UNORM:
3814 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
3815 break;
3816 case WINED3DFMT_D24_UNORM_S8_UINT:
3817 case WINED3DFMT_X8D24_UNORM:
3818 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
3819 break;
3820 case WINED3DFMT_D32_UNORM:
3821 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
3822 break;
3823 default:
3824 depth = 0.0f;
3825 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format_desc->format));
3826 }
3827
3828 return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
3829 DestRect == NULL ? 0 : 1,
3830 (const WINED3DRECT *)DestRect,
3831 WINED3DCLEAR_ZBUFFER,
3832 0x00000000,
3833 depth,
3834 0x00000000);
3835 }
3836
3837 FIXME("(%p): Unsupp depthstencil blit\n", This);
3838 return WINED3DERR_INVALIDCALL;
3839}
3840
3841static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
3842 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3843 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3844 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3845 IWineD3DDeviceImpl *myDevice = This->resource.device;
3846
3847 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3848 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3849
3850 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
3851 {
3852 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3853 return WINEDDERR_SURFACEBUSY;
3854 }
3855
3856 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3857 * except depth blits, which seem to work
3858 */
3859 if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
3860 if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
3861 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3862 return WINED3DERR_INVALIDCALL;
3863 } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3864 TRACE("Z Blit override handled the blit\n");
3865 return WINED3D_OK;
3866 }
3867 }
3868
3869 /* Special cases for RenderTargets */
3870 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3871 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3872 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
3873 }
3874
3875 /* For the rest call the X11 surface implementation.
3876 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3877 * other Blts are rather rare
3878 */
3879 return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3880}
3881
3882static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
3883 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
3884{
3885 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3886 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3887 IWineD3DDeviceImpl *myDevice = This->resource.device;
3888
3889 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3890
3891 if ( (This->Flags & SFLAG_LOCKED) || (srcImpl->Flags & SFLAG_LOCKED))
3892 {
3893 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3894 return WINEDDERR_SURFACEBUSY;
3895 }
3896
3897 if(myDevice->inScene &&
3898 (iface == myDevice->stencilBufferTarget ||
3899 (Source == myDevice->stencilBufferTarget))) {
3900 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3901 return WINED3DERR_INVALIDCALL;
3902 }
3903
3904 /* Special cases for RenderTargets */
3905 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3906 (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
3907
3908 RECT SrcRect, DstRect;
3909 DWORD Flags=0;
3910
3911 surface_get_rect(srcImpl, rsrc, &SrcRect);
3912
3913 DstRect.left = dstx;
3914 DstRect.top=dsty;
3915 DstRect.right = dstx + SrcRect.right - SrcRect.left;
3916 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3917
3918 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3919 if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3920 Flags |= WINEDDBLT_KEYSRC;
3921 if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3922 Flags |= WINEDDBLT_KEYDEST;
3923 if(trans & WINEDDBLTFAST_WAIT)
3924 Flags |= WINEDDBLT_WAIT;
3925 if(trans & WINEDDBLTFAST_DONOTWAIT)
3926 Flags |= WINEDDBLT_DONOTWAIT;
3927
3928 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
3929 }
3930
3931
3932 return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3933}
3934
3935static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface)
3936{
3937 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3938 RGBQUAD col[256];
3939 IWineD3DPaletteImpl *pal = This->palette;
3940 unsigned int n;
3941 TRACE("(%p)\n", This);
3942
3943 if (!pal) return WINED3D_OK;
3944
3945 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
3946 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
3947 {
3948 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3949 {
3950 /* Make sure the texture is up to date. This call doesn't do anything if the texture is already up to date. */
3951 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
3952
3953 /* We want to force a palette refresh, so mark the drawable as not being up to date */
3954 IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
3955 } else {
3956 if(!(This->Flags & SFLAG_INSYSMEM)) {
3957 TRACE("Palette changed with surface that does not have an up to date system memory copy\n");
3958 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
3959 }
3960 TRACE("Dirtifying surface\n");
3961 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
3962 }
3963 }
3964
3965 if(This->Flags & SFLAG_DIBSECTION) {
3966 TRACE("(%p): Updating the hdc's palette\n", This);
3967 for (n=0; n<256; n++) {
3968 col[n].rgbRed = pal->palents[n].peRed;
3969 col[n].rgbGreen = pal->palents[n].peGreen;
3970 col[n].rgbBlue = pal->palents[n].peBlue;
3971 col[n].rgbReserved = 0;
3972 }
3973 SetDIBColorTable(This->hDC, 0, 256, col);
3974 }
3975
3976 /* Propagate the changes to the drawable when we have a palette. */
3977 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3978 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, NULL);
3979
3980 return WINED3D_OK;
3981}
3982
3983#ifdef VBOXWDDM
3984static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect);
3985#endif
3986
3987static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3988 /** Check against the maximum texture sizes supported by the video card **/
3989 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3990 const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
3991 unsigned int pow2Width, pow2Height;
3992
3993 This->texture_name = 0;
3994 This->texture_target = GL_TEXTURE_2D;
3995
3996 /* Non-power2 support */
3997 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINE_NORMALIZED_TEXRECT])
3998 {
3999 pow2Width = This->currentDesc.Width;
4000 pow2Height = This->currentDesc.Height;
4001 }
4002 else
4003 {
4004 /* Find the nearest pow2 match */
4005 pow2Width = pow2Height = 1;
4006 while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
4007 while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
4008 }
4009 This->pow2Width = pow2Width;
4010 This->pow2Height = pow2Height;
4011
4012 if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
4013 /** TODO: add support for non power two compressed textures **/
4014 if (This->resource.format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
4015 {
4016 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
4017 This, This->currentDesc.Width, This->currentDesc.Height);
4018 return WINED3DERR_NOTAVAILABLE;
4019 }
4020 }
4021
4022 if(pow2Width != This->currentDesc.Width ||
4023 pow2Height != This->currentDesc.Height) {
4024 This->Flags |= SFLAG_NONPOW2;
4025 }
4026
4027 TRACE("%p\n", This);
4028 if ((This->pow2Width > gl_info->limits.texture_size || This->pow2Height > gl_info->limits.texture_size)
4029 && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4030 {
4031 /* one of three options
4032 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
4033 2: Set the texture to the maximum size (bad idea)
4034 3: WARN and return WINED3DERR_NOTAVAILABLE;
4035 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
4036 */
4037 if(This->resource.pool == WINED3DPOOL_DEFAULT || This->resource.pool == WINED3DPOOL_MANAGED)
4038 {
4039 WARN("(%p) Unable to allocate a surface which exceeds the maximum OpenGL texture size\n", This);
4040 return WINED3DERR_NOTAVAILABLE;
4041 }
4042
4043 /* We should never use this surface in combination with OpenGL! */
4044 TRACE("(%p) Creating an oversized surface: %ux%u\n", This, This->pow2Width, This->pow2Height);
4045 }
4046 else
4047 {
4048 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
4049 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
4050 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
4051 */
4052 if (This->Flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
4053 && !(This->resource.format_desc->format == WINED3DFMT_P8_UINT
4054 && gl_info->supported[EXT_PALETTED_TEXTURE]
4055 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
4056 {
4057 This->texture_target = GL_TEXTURE_RECTANGLE_ARB;
4058 This->pow2Width = This->currentDesc.Width;
4059 This->pow2Height = This->currentDesc.Height;
4060 This->Flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
4061 }
4062 }
4063
4064 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4065 switch(wined3d_settings.offscreen_rendering_mode) {
4066 case ORM_FBO: This->get_drawable_size = get_drawable_size_fbo; break;
4067 case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4068 }
4069 }
4070
4071 This->Flags |= SFLAG_INSYSMEM;
4072
4073 return WINED3D_OK;
4074}
4075
4076/* GL locking is done by the caller */
4077static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
4078 GLuint texture, GLsizei w, GLsizei h, GLenum target)
4079{
4080 IWineD3DDeviceImpl *device = This->resource.device;
4081 struct blt_info info;
4082 GLint old_binding = 0;
4083
4084 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4085
4086 glDisable(GL_CULL_FACE);
4087 glDisable(GL_BLEND);
4088 glDisable(GL_ALPHA_TEST);
4089 glDisable(GL_SCISSOR_TEST);
4090 glDisable(GL_STENCIL_TEST);
4091 glEnable(GL_DEPTH_TEST);
4092 glDepthFunc(GL_ALWAYS);
4093 glDepthMask(GL_TRUE);
4094 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4095 glViewport(0, 0, w, h);
4096
4097 surface_get_blt_info(target, NULL, w, h, &info);
4098 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4099 glGetIntegerv(info.binding, &old_binding);
4100 glBindTexture(info.bind_target, texture);
4101
4102 device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device, info.tex_type);
4103
4104 glBegin(GL_TRIANGLE_STRIP);
4105 glTexCoord3fv(info.coords[0]);
4106 glVertex2f(-1.0f, -1.0f);
4107 glTexCoord3fv(info.coords[1]);
4108 glVertex2f(1.0f, -1.0f);
4109 glTexCoord3fv(info.coords[2]);
4110 glVertex2f(-1.0f, 1.0f);
4111 glTexCoord3fv(info.coords[3]);
4112 glVertex2f(1.0f, 1.0f);
4113 glEnd();
4114
4115 glBindTexture(info.bind_target, old_binding);
4116
4117 glPopAttrib();
4118
4119 device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
4120}
4121
4122void surface_modify_ds_location(IWineD3DSurface *iface, DWORD location) {
4123 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4124
4125 TRACE("(%p) New location %#x\n", This, location);
4126
4127 if (location & ~SFLAG_DS_LOCATIONS) {
4128 FIXME("(%p) Invalid location (%#x) specified\n", This, location);
4129 }
4130
4131 This->Flags &= ~SFLAG_DS_LOCATIONS;
4132 This->Flags |= location;
4133}
4134
4135/* Context activation is done by the caller. */
4136void surface_load_ds_location(IWineD3DSurface *iface, struct wined3d_context *context, DWORD location)
4137{
4138 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4139 IWineD3DDeviceImpl *device = This->resource.device;
4140 const struct wined3d_gl_info *gl_info = context->gl_info;
4141
4142 TRACE("(%p) New location %#x\n", This, location);
4143
4144 /* TODO: Make this work for modes other than FBO */
4145 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4146
4147 if (This->Flags & location) {
4148 TRACE("(%p) Location (%#x) is already up to date\n", This, location);
4149 return;
4150 }
4151
4152 if (This->current_renderbuffer) {
4153 FIXME("(%p) Not supported with fixed up depth stencil\n", This);
4154 return;
4155 }
4156
4157 if (location == SFLAG_DS_OFFSCREEN) {
4158 if (This->Flags & SFLAG_DS_ONSCREEN) {
4159 GLint old_binding = 0;
4160 GLenum bind_target;
4161
4162 TRACE("(%p) Copying onscreen depth buffer to depth texture\n", This);
4163
4164 ENTER_GL();
4165
4166 if (!device->depth_blt_texture) {
4167 glGenTextures(1, &device->depth_blt_texture);
4168 }
4169
4170 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4171 * directly on the FBO texture. That's because we need to flip. */
4172 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4173 if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4174 {
4175 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4176 bind_target = GL_TEXTURE_RECTANGLE_ARB;
4177 } else {
4178 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4179 bind_target = GL_TEXTURE_2D;
4180 }
4181 glBindTexture(bind_target, device->depth_blt_texture);
4182 glCopyTexImage2D(bind_target, This->texture_level, This->resource.format_desc->glInternal,
4183 0, 0, This->currentDesc.Width, This->currentDesc.Height, 0);
4184 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4185 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4186 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4187 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4188 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4189 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4190 glBindTexture(bind_target, old_binding);
4191
4192 /* Setup the destination */
4193 if (!device->depth_blt_rb) {
4194 gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
4195 checkGLcall("glGenRenderbuffersEXT");
4196 }
4197 if (device->depth_blt_rb_w != This->currentDesc.Width
4198 || device->depth_blt_rb_h != This->currentDesc.Height) {
4199 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
4200 checkGLcall("glBindRenderbufferEXT");
4201 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
4202 This->currentDesc.Width, This->currentDesc.Height);
4203 checkGLcall("glRenderbufferStorageEXT");
4204 device->depth_blt_rb_w = This->currentDesc.Width;
4205 device->depth_blt_rb_h = This->currentDesc.Height;
4206 }
4207
4208 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4209 gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
4210 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
4211 checkGLcall("glFramebufferRenderbufferEXT");
4212 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, This, FALSE);
4213
4214 /* Do the actual blit */
4215 surface_depth_blt(This, gl_info, device->depth_blt_texture,
4216 This->currentDesc.Width, This->currentDesc.Height, bind_target);
4217 checkGLcall("depth_blt");
4218
4219 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4220 else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4221
4222 LEAVE_GL();
4223
4224 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4225 }
4226 else
4227 {
4228 FIXME("No up to date depth stencil location\n");
4229 }
4230 } else if (location == SFLAG_DS_ONSCREEN) {
4231 if (This->Flags & SFLAG_DS_OFFSCREEN) {
4232 TRACE("(%p) Copying depth texture to onscreen depth buffer\n", This);
4233
4234 ENTER_GL();
4235
4236 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4237 surface_depth_blt(This, gl_info, This->texture_name,
4238 This->currentDesc.Width, This->currentDesc.Height, This->texture_target);
4239 checkGLcall("depth_blt");
4240
4241 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4242
4243 LEAVE_GL();
4244
4245 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4246 }
4247 else
4248 {
4249 FIXME("No up to date depth stencil location\n");
4250 }
4251 } else {
4252 ERR("(%p) Invalid location (%#x) specified\n", This, location);
4253 }
4254
4255 This->Flags |= location;
4256}
4257
4258static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
4259 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4260 IWineD3DBaseTexture *texture;
4261 IWineD3DSurfaceImpl *overlay;
4262
4263 TRACE("(%p)->(%s, %s)\n", iface, debug_surflocation(flag),
4264 persistent ? "TRUE" : "FALSE");
4265
4266 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4267 if (surface_is_offscreen(iface))
4268 {
4269 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4270 if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4271 }
4272 else
4273 {
4274 TRACE("Surface %p is an onscreen surface\n", iface);
4275 }
4276 }
4277
4278 if(persistent) {
4279 if(((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) ||
4280 ((This->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX))) {
4281 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4282 TRACE("Passing to container\n");
4283 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4284 IWineD3DBaseTexture_Release(texture);
4285 }
4286 }
4287
4288 This->Flags &= ~SFLAG_LOCATIONS;
4289 This->Flags |= flag;
4290
4291 /* Redraw emulated overlays, if any */
4292 if(flag & SFLAG_INDRAWABLE && !list_empty(&This->overlays)) {
4293 LIST_FOR_EACH_ENTRY(overlay, &This->overlays, IWineD3DSurfaceImpl, overlay_entry) {
4294 IWineD3DSurface_DrawOverlay((IWineD3DSurface *) overlay);
4295 }
4296 }
4297 } else {
4298 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) {
4299 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4300 TRACE("Passing to container\n");
4301 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4302 IWineD3DBaseTexture_Release(texture);
4303 }
4304 }
4305
4306 This->Flags &= ~flag;
4307 }
4308
4309#ifdef VBOXWDDM
4310 if(VBOXSHRC_IS_INITIALIZED(This)) {
4311 /* with the shared resource only texture can be considered valid
4312 * to make sure changes done to the resource in the other device context are visible
4313 * because the resource contents is shared via texture.
4314 * This is why we ensure texture location is the one and only which is always valid */
4315 if(!(This->Flags & SFLAG_INTEXTURE)) {
4316 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
4317 } else {
4318 This->Flags &= ~SFLAG_LOCATIONS;
4319 This->Flags |= SFLAG_INTEXTURE;
4320 }
4321 }
4322#endif
4323
4324 if(!(This->Flags & SFLAG_LOCATIONS)) {
4325 ERR("%p: Surface does not have any up to date location\n", This);
4326 }
4327}
4328
4329static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in)
4330{
4331 IWineD3DDeviceImpl *device = This->resource.device;
4332 IWineD3DSwapChainImpl *swapchain;
4333 struct wined3d_context *context;
4334 RECT src_rect, dst_rect;
4335
4336 surface_get_rect(This, rect_in, &src_rect);
4337
4338 context = context_acquire(device, (IWineD3DSurface*)This, CTXUSAGE_BLIT);
4339 if (context->render_offscreen)
4340 {
4341 dst_rect.left = src_rect.left;
4342 dst_rect.right = src_rect.right;
4343 dst_rect.top = src_rect.bottom;
4344 dst_rect.bottom = src_rect.top;
4345 }
4346 else
4347 {
4348 dst_rect = src_rect;
4349 }
4350
4351 device->blitter->set_shader((IWineD3DDevice *) device, This);
4352
4353 ENTER_GL();
4354 draw_textured_quad(This, &src_rect, &dst_rect, WINED3DTEXF_POINT);
4355 LEAVE_GL();
4356
4357 device->blitter->set_shader((IWineD3DDevice *) device, This);
4358
4359 swapchain = (This->Flags & SFLAG_SWAPCHAIN) ? (IWineD3DSwapChainImpl *)This->container : NULL;
4360 if (wined3d_settings.strict_draw_ordering || (swapchain
4361 && ((IWineD3DSurface *)This == swapchain->frontBuffer
4362 || swapchain->num_contexts > 1)))
4363 wglFlush(); /* Flush to ensure ordering across contexts. */
4364
4365 context_release(context);
4366}
4367
4368/*****************************************************************************
4369 * IWineD3DSurface::LoadLocation
4370 *
4371 * Copies the current surface data from wherever it is to the requested
4372 * location. The location is one of the surface flags, SFLAG_INSYSMEM,
4373 * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
4374 * multiple locations, the gl texture is preferred over the drawable, which is
4375 * preferred over system memory. The PBO counts as system memory. If rect is
4376 * not NULL, only the specified rectangle is copied (only supported for
4377 * sysmem<->drawable copies at the moment). If rect is NULL, the destination
4378 * location is marked up to date after the copy.
4379 *
4380 * Parameters:
4381 * flag: Surface location flag to be updated
4382 * rect: rectangle to be copied
4383 *
4384 * Returns:
4385 * WINED3D_OK on success
4386 * WINED3DERR_DEVICELOST on an internal error
4387 *
4388 *****************************************************************************/
4389static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
4390 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4391 IWineD3DDeviceImpl *device = This->resource.device;
4392 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4393 struct wined3d_format_desc desc;
4394 CONVERT_TYPES convert;
4395 int width, pitch, outpitch;
4396 BYTE *mem;
4397 BOOL drawable_read_ok = TRUE;
4398 BOOL in_fbo = FALSE;
4399
4400 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4401 if (surface_is_offscreen(iface))
4402 {
4403 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
4404 * Prefer SFLAG_INTEXTURE. */
4405 if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
4406 drawable_read_ok = FALSE;
4407 in_fbo = TRUE;
4408 }
4409 else
4410 {
4411 TRACE("Surface %p is an onscreen surface\n", iface);
4412 }
4413 }
4414
4415 TRACE("(%p)->(%s, %p)\n", iface, debug_surflocation(flag), rect);
4416 if(rect) {
4417 TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
4418 }
4419
4420 if(This->Flags & flag) {
4421 TRACE("Location already up to date\n");
4422 return WINED3D_OK;
4423 }
4424
4425 if(!(This->Flags & SFLAG_LOCATIONS)) {
4426 ERR("%p: Surface does not have any up to date location\n", This);
4427 This->Flags |= SFLAG_LOST;
4428 return WINED3DERR_DEVICELOST;
4429 }
4430
4431 if(flag == SFLAG_INSYSMEM) {
4432 surface_prepare_system_memory(This);
4433
4434 /* Download the surface to system memory */
4435 if (This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
4436 {
4437 struct wined3d_context *context = NULL;
4438
4439 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4440
4441 surface_bind_and_dirtify(This, !(This->Flags & SFLAG_INTEXTURE));
4442 surface_download_data(This, gl_info);
4443
4444 if (context) context_release(context);
4445 }
4446 else
4447 {
4448 /* Note: It might be faster to download into a texture first. */
4449 read_from_framebuffer(This, rect,
4450 This->resource.allocatedMemory,
4451 IWineD3DSurface_GetPitch(iface));
4452 }
4453 } else if(flag == SFLAG_INDRAWABLE) {
4454 if(This->Flags & SFLAG_INTEXTURE) {
4455 surface_blt_to_drawable(This, rect);
4456 } else {
4457 int byte_count;
4458 if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) {
4459 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
4460 * values, otherwise we get incorrect values in the target. For now go the slow way
4461 * via a system memory copy
4462 */
4463 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4464 }
4465
4466 d3dfmt_get_conv(This, FALSE /* We need color keying */, FALSE /* We won't use textures */, &desc, &convert);
4467
4468 /* The width is in 'length' not in bytes */
4469 width = This->currentDesc.Width;
4470 pitch = IWineD3DSurface_GetPitch(iface);
4471
4472 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4473 * but it isn't set (yet) in all cases it is getting called. */
4474 if ((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO))
4475 {
4476 struct wined3d_context *context = NULL;
4477
4478 TRACE("Removing the pbo attached to surface %p\n", This);
4479
4480 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4481 surface_remove_pbo(This, gl_info);
4482 if (context) context_release(context);
4483 }
4484
4485 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4486 int height = This->currentDesc.Height;
4487 byte_count = desc.conv_byte_count;
4488
4489 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4490 outpitch = width * byte_count;
4491 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4492
4493 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4494 if(!mem) {
4495 ERR("Out of memory %d, %d!\n", outpitch, height);
4496 return WINED3DERR_OUTOFVIDEOMEMORY;
4497 }
4498 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4499
4500 This->Flags |= SFLAG_CONVERTED;
4501 } else {
4502 This->Flags &= ~SFLAG_CONVERTED;
4503 mem = This->resource.allocatedMemory;
4504 byte_count = desc.byte_count;
4505 }
4506
4507 flush_to_framebuffer_drawpixels(This, desc.glFormat, desc.glType, byte_count, mem);
4508
4509 /* Don't delete PBO memory */
4510 if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4511 HeapFree(GetProcessHeap(), 0, mem);
4512 }
4513 } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ {
4514 if (drawable_read_ok && (This->Flags & SFLAG_INDRAWABLE)) {
4515 read_from_framebuffer_texture(This, flag == SFLAG_INSRGBTEX);
4516 }
4517 else
4518 {
4519 /* Upload from system memory */
4520 BOOL srgb = flag == SFLAG_INSRGBTEX;
4521 struct wined3d_context *context = NULL;
4522
4523 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */,
4524 &desc, &convert);
4525
4526 if(srgb) {
4527 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) {
4528 /* Performance warning ... */
4529 FIXME("%p: Downloading rgb texture to reload it as srgb\n", This);
4530 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4531 }
4532 } else {
4533 if((This->Flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX) {
4534 /* Performance warning ... */
4535 FIXME("%p: Downloading srgb texture to reload it as rgb\n", This);
4536 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4537 }
4538 }
4539 if(!(This->Flags & SFLAG_INSYSMEM)) {
4540 /* Should not happen */
4541 ERR("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set\n");
4542 /* Lets hope we get it from somewhere... */
4543 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4544 }
4545
4546 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4547
4548 surface_prepare_texture(This, gl_info, srgb);
4549 surface_bind_and_dirtify(This, srgb);
4550
4551 if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
4552 This->Flags |= SFLAG_GLCKEY;
4553 This->glCKey = This->SrcBltCKey;
4554 }
4555 else This->Flags &= ~SFLAG_GLCKEY;
4556
4557 /* The width is in 'length' not in bytes */
4558 width = This->currentDesc.Width;
4559 pitch = IWineD3DSurface_GetPitch(iface);
4560
4561 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4562 * but it isn't set (yet) in all cases it is getting called. */
4563 if((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO)) {
4564 TRACE("Removing the pbo attached to surface %p\n", This);
4565 surface_remove_pbo(This, gl_info);
4566 }
4567
4568 if(desc.convert) {
4569 /* This code is entered for texture formats which need a fixup. */
4570 int height = This->currentDesc.Height;
4571
4572 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4573 outpitch = width * desc.conv_byte_count;
4574 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4575
4576 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4577 if(!mem) {
4578 ERR("Out of memory %d, %d!\n", outpitch, height);
4579 if (context) context_release(context);
4580 return WINED3DERR_OUTOFVIDEOMEMORY;
4581 }
4582 desc.convert(This->resource.allocatedMemory, mem, pitch, width, height);
4583 } else if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4584 /* This code is only entered for color keying fixups */
4585 int height = This->currentDesc.Height;
4586
4587 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4588 outpitch = width * desc.conv_byte_count;
4589 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4590
4591 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4592 if(!mem) {
4593 ERR("Out of memory %d, %d!\n", outpitch, height);
4594 if (context) context_release(context);
4595 return WINED3DERR_OUTOFVIDEOMEMORY;
4596 }
4597 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4598 } else {
4599 mem = This->resource.allocatedMemory;
4600 }
4601
4602 /* Make sure the correct pitch is used */
4603 ENTER_GL();
4604 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
4605 LEAVE_GL();
4606
4607 if (mem || (This->Flags & SFLAG_PBO))
4608 surface_upload_data(This, gl_info, &desc, srgb, mem);
4609
4610 /* Restore the default pitch */
4611 ENTER_GL();
4612 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4613 LEAVE_GL();
4614
4615 if (context) context_release(context);
4616
4617 /* Don't delete PBO memory */
4618 if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4619 HeapFree(GetProcessHeap(), 0, mem);
4620 }
4621 }
4622
4623#ifdef VBOXWDDM
4624 if (VBOXSHRC_IS_INITIALIZED(This))
4625 {
4626 /* with the shared resource only texture can be considered valid
4627 * to make sure changes done to the resource in the other device context are visible
4628 * because the resource contents is shared via texture.
4629 * One can load and use other locations as needed,
4630 * but they should be reloaded each time on each usage */
4631 Assert(!!(This->Flags & SFLAG_INTEXTURE) || !!(flag & SFLAG_INTEXTURE));
4632 This->Flags &= ~SFLAG_LOCATIONS;
4633 This->Flags |= SFLAG_INTEXTURE;
4634 /* @todo: SFLAG_INSRGBTEX ?? */
4635// if (in_fbo)
4636// {
4637// This->Flags |= SFLAG_INDRAWABLE;
4638// }
4639 }
4640 else
4641#endif
4642 {
4643 if(rect == NULL) {
4644 This->Flags |= flag;
4645 }
4646
4647 if (in_fbo && (This->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE))) {
4648 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4649 This->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4650 }
4651 }
4652
4653 return WINED3D_OK;
4654}
4655
4656static HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container)
4657{
4658 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4659 IWineD3DSwapChain *swapchain = NULL;
4660
4661 /* Update the drawable size method */
4662 if(container) {
4663 IWineD3DBase_QueryInterface(container, &IID_IWineD3DSwapChain, (void **) &swapchain);
4664 }
4665 if(swapchain) {
4666 This->get_drawable_size = get_drawable_size_swapchain;
4667 IWineD3DSwapChain_Release(swapchain);
4668 } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4669 switch(wined3d_settings.offscreen_rendering_mode) {
4670 case ORM_FBO: This->get_drawable_size = get_drawable_size_fbo; break;
4671 case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4672 }
4673 }
4674
4675 return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
4676}
4677
4678static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
4679 return SURFACE_OPENGL;
4680}
4681
4682static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
4683 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4684 HRESULT hr;
4685
4686 /* If there's no destination surface there is nothing to do */
4687 if(!This->overlay_dest) return WINED3D_OK;
4688
4689 /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
4690 * update the overlay. Prevent an endless recursion
4691 */
4692 if(This->overlay_dest->Flags & SFLAG_INOVERLAYDRAW) {
4693 return WINED3D_OK;
4694 }
4695 This->overlay_dest->Flags |= SFLAG_INOVERLAYDRAW;
4696 hr = IWineD3DSurfaceImpl_Blt((IWineD3DSurface *) This->overlay_dest, &This->overlay_destrect,
4697 iface, &This->overlay_srcrect, WINEDDBLT_WAIT,
4698 NULL, WINED3DTEXF_LINEAR);
4699 This->overlay_dest->Flags &= ~SFLAG_INOVERLAYDRAW;
4700
4701 return hr;
4702}
4703
4704BOOL surface_is_offscreen(IWineD3DSurface *iface)
4705{
4706 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4707 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) This->container;
4708
4709 /* Not on a swapchain - must be offscreen */
4710 if (!(This->Flags & SFLAG_SWAPCHAIN)) return TRUE;
4711
4712 /* The front buffer is always onscreen */
4713 if(iface == swapchain->frontBuffer) return FALSE;
4714
4715 /* If the swapchain is rendered to an FBO, the backbuffer is
4716 * offscreen, otherwise onscreen */
4717 return swapchain->render_to_fbo;
4718}
4719
4720const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
4721{
4722 /* IUnknown */
4723 IWineD3DBaseSurfaceImpl_QueryInterface,
4724 IWineD3DBaseSurfaceImpl_AddRef,
4725 IWineD3DSurfaceImpl_Release,
4726 /* IWineD3DResource */
4727 IWineD3DBaseSurfaceImpl_GetParent,
4728 IWineD3DBaseSurfaceImpl_SetPrivateData,
4729 IWineD3DBaseSurfaceImpl_GetPrivateData,
4730 IWineD3DBaseSurfaceImpl_FreePrivateData,
4731 IWineD3DBaseSurfaceImpl_SetPriority,
4732 IWineD3DBaseSurfaceImpl_GetPriority,
4733 IWineD3DSurfaceImpl_PreLoad,
4734 IWineD3DSurfaceImpl_UnLoad,
4735 IWineD3DBaseSurfaceImpl_GetType,
4736 /* IWineD3DSurface */
4737 IWineD3DBaseSurfaceImpl_GetContainer,
4738 IWineD3DBaseSurfaceImpl_GetDesc,
4739 IWineD3DSurfaceImpl_LockRect,
4740 IWineD3DSurfaceImpl_UnlockRect,
4741 IWineD3DSurfaceImpl_GetDC,
4742 IWineD3DSurfaceImpl_ReleaseDC,
4743 IWineD3DSurfaceImpl_Flip,
4744 IWineD3DSurfaceImpl_Blt,
4745 IWineD3DBaseSurfaceImpl_GetBltStatus,
4746 IWineD3DBaseSurfaceImpl_GetFlipStatus,
4747 IWineD3DBaseSurfaceImpl_IsLost,
4748 IWineD3DBaseSurfaceImpl_Restore,
4749 IWineD3DSurfaceImpl_BltFast,
4750 IWineD3DBaseSurfaceImpl_GetPalette,
4751 IWineD3DBaseSurfaceImpl_SetPalette,
4752 IWineD3DSurfaceImpl_RealizePalette,
4753 IWineD3DBaseSurfaceImpl_SetColorKey,
4754 IWineD3DBaseSurfaceImpl_GetPitch,
4755 IWineD3DSurfaceImpl_SetMem,
4756 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
4757 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
4758 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
4759 IWineD3DBaseSurfaceImpl_UpdateOverlay,
4760 IWineD3DBaseSurfaceImpl_SetClipper,
4761 IWineD3DBaseSurfaceImpl_GetClipper,
4762 /* Internal use: */
4763 IWineD3DSurfaceImpl_LoadTexture,
4764 IWineD3DSurfaceImpl_BindTexture,
4765 IWineD3DSurfaceImpl_SaveSnapshot,
4766 IWineD3DSurfaceImpl_SetContainer,
4767 IWineD3DBaseSurfaceImpl_GetData,
4768 IWineD3DSurfaceImpl_SetFormat,
4769 IWineD3DSurfaceImpl_PrivateSetup,
4770 IWineD3DSurfaceImpl_ModifyLocation,
4771 IWineD3DSurfaceImpl_LoadLocation,
4772 IWineD3DSurfaceImpl_GetImplType,
4773 IWineD3DSurfaceImpl_DrawOverlay
4774};
4775
4776static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
4777/* Context activation is done by the caller. */
4778static void ffp_blit_free(IWineD3DDevice *iface) { }
4779
4780/* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
4781/* Context activation is done by the caller. */
4782static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
4783{
4784 BYTE table[256][4];
4785 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
4786
4787 d3dfmt_p8_init_palette(surface, table, colorkey_active);
4788
4789 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
4790 ENTER_GL();
4791 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
4792 LEAVE_GL();
4793}
4794
4795/* Context activation is done by the caller. */
4796static HRESULT ffp_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4797{
4798 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4799 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4800 enum complex_fixup fixup = get_complex_fixup(surface->resource.format_desc->color_fixup);
4801
4802 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
4803 * else the surface is converted in software at upload time in LoadLocation.
4804 */
4805 if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4806 ffp_blit_p8_upload_palette(surface, gl_info);
4807
4808 ENTER_GL();
4809 glEnable(surface->texture_target);
4810 checkGLcall("glEnable(surface->texture_target)");
4811 LEAVE_GL();
4812 return WINED3D_OK;
4813}
4814
4815/* Context activation is done by the caller. */
4816static void ffp_blit_unset(IWineD3DDevice *iface)
4817{
4818 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4819 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4820
4821 ENTER_GL();
4822 glDisable(GL_TEXTURE_2D);
4823 checkGLcall("glDisable(GL_TEXTURE_2D)");
4824 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
4825 {
4826 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
4827 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4828 }
4829 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
4830 {
4831 glDisable(GL_TEXTURE_RECTANGLE_ARB);
4832 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4833 }
4834 LEAVE_GL();
4835}
4836
4837static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4838 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4839 const struct wined3d_format_desc *src_format_desc,
4840 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4841 const struct wined3d_format_desc *dst_format_desc)
4842{
4843 enum complex_fixup src_fixup;
4844
4845 if (blit_op == BLIT_OP_COLOR_FILL)
4846 {
4847 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4848 {
4849 TRACE("Color fill not supported\n");
4850 return FALSE;
4851 }
4852
4853 return TRUE;
4854 }
4855
4856 src_fixup = get_complex_fixup(src_format_desc->color_fixup);
4857 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
4858 {
4859 TRACE("Checking support for fixup:\n");
4860 dump_color_fixup_desc(src_format_desc->color_fixup);
4861 }
4862
4863 if (blit_op != BLIT_OP_BLIT)
4864 {
4865 TRACE("Unsupported blit_op=%d\n", blit_op);
4866 return FALSE;
4867 }
4868
4869 if (!is_identity_fixup(dst_format_desc->color_fixup))
4870 {
4871 TRACE("Destination fixups are not supported\n");
4872 return FALSE;
4873 }
4874
4875 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4876 {
4877 TRACE("P8 fixup supported\n");
4878 return TRUE;
4879 }
4880
4881 /* We only support identity conversions. */
4882 if (is_identity_fixup(src_format_desc->color_fixup))
4883 {
4884 TRACE("[OK]\n");
4885 return TRUE;
4886 }
4887
4888 TRACE("[FAILED]\n");
4889 return FALSE;
4890}
4891
4892static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4893{
4894 return IWineD3DDeviceImpl_ClearSurface(device, dst_surface, 1 /* Number of rectangles */,
4895 (const WINED3DRECT*)dst_rect, WINED3DCLEAR_TARGET, fill_color, 0.0f /* Z */, 0 /* Stencil */);
4896}
4897
4898const struct blit_shader ffp_blit = {
4899 ffp_blit_alloc,
4900 ffp_blit_free,
4901 ffp_blit_set,
4902 ffp_blit_unset,
4903 ffp_blit_supported,
4904 ffp_blit_color_fill
4905};
4906
4907static HRESULT cpu_blit_alloc(IWineD3DDevice *iface)
4908{
4909 return WINED3D_OK;
4910}
4911
4912/* Context activation is done by the caller. */
4913static void cpu_blit_free(IWineD3DDevice *iface)
4914{
4915}
4916
4917/* Context activation is done by the caller. */
4918static HRESULT cpu_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4919{
4920 return WINED3D_OK;
4921}
4922
4923/* Context activation is done by the caller. */
4924static void cpu_blit_unset(IWineD3DDevice *iface)
4925{
4926}
4927
4928static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4929 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4930 const struct wined3d_format_desc *src_format_desc,
4931 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4932 const struct wined3d_format_desc *dst_format_desc)
4933{
4934 if (blit_op == BLIT_OP_COLOR_FILL)
4935 {
4936 return TRUE;
4937 }
4938
4939 return FALSE;
4940}
4941
4942static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4943{
4944 WINEDDBLTFX BltFx;
4945 memset(&BltFx, 0, sizeof(BltFx));
4946 BltFx.dwSize = sizeof(BltFx);
4947 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(fill_color, dst_surface->resource.format_desc->format);
4948 return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
4949}
4950
4951const struct blit_shader cpu_blit = {
4952 cpu_blit_alloc,
4953 cpu_blit_free,
4954 cpu_blit_set,
4955 cpu_blit_unset,
4956 cpu_blit_supported,
4957 cpu_blit_color_fill
4958};
4959
4960static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4961 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4962 const struct wined3d_format_desc *src_format_desc,
4963 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4964 const struct wined3d_format_desc *dst_format_desc)
4965{
4966 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
4967 return FALSE;
4968
4969 /* We only support blitting. Things like color keying / color fill should
4970 * be handled by other blitters.
4971 */
4972 if (blit_op != BLIT_OP_BLIT)
4973 return FALSE;
4974
4975 /* Source and/or destination need to be on the GL side */
4976 if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
4977 return FALSE;
4978
4979 if(!((src_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET))
4980 && ((dst_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
4981 return FALSE;
4982
4983 if (!is_identity_fixup(src_format_desc->color_fixup) ||
4984 !is_identity_fixup(dst_format_desc->color_fixup))
4985 return FALSE;
4986
4987 if (!(src_format_desc->format == dst_format_desc->format
4988 || (is_identity_fixup(src_format_desc->color_fixup)
4989 && is_identity_fixup(dst_format_desc->color_fixup))))
4990 return FALSE;
4991
4992 return TRUE;
4993}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette