VirtualBox

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

Last change on this file since 39649 was 39649, checked in by vboxsync, 13 years ago

wine/wddm: faster blits

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