VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine_new/wined3d/surface.c@ 48073

Last change on this file since 48073 was 48073, checked in by vboxsync, 12 years ago

wined3d: update to wine 1.6

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 277.5 KB
Line 
1/*
2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29#include "config.h"
30#include "wine/port.h"
31#include "wined3d_private.h"
32#ifdef VBOX_WITH_WINE_FIXES
33# include <float.h>
34#endif
35
36WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
38WINE_DECLARE_DEBUG_CHANNEL(d3d);
39
40#ifdef VBOX_WITH_WDDM
41void surface_shrc_lock_surf(struct wined3d_surface *surf)
42{
43 VBOXSHRC_LOCK(surf);
44}
45
46void surface_shrc_unlock_surf(struct wined3d_surface *surf)
47{
48 VBOXSHRC_UNLOCK(surf);
49 if (VBOXSHRC_IS_LOCKED(surf))
50 return;
51
52 /* perform data->texture synchronization */
53 surface_load_location(surf, SFLAG_INTEXTURE, NULL);
54}
55
56void surface_shrc_lock(struct wined3d_surface *surf)
57{
58 if (!VBOXSHRC_IS_SHARED(surf))
59 return;
60
61 surface_shrc_lock_surf(surf);
62}
63
64void surface_shrc_unlock(struct wined3d_surface *surf)
65{
66 if (!VBOXSHRC_IS_SHARED(surf))
67 return;
68 surface_shrc_unlock_surf(surf);
69}
70#endif
71
72static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
73 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
74 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter);
75static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
76 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
77 enum wined3d_texture_filter_type filter);
78
79static void surface_cleanup(struct wined3d_surface *surface)
80{
81 struct wined3d_surface *overlay, *cur;
82
83 TRACE("surface %p.\n", surface);
84
85 if (surface->texture_name || (surface->flags & SFLAG_PBO)
86 || surface->rb_multisample || surface->rb_resolved
87 || !list_empty(&surface->renderbuffers))
88 {
89 struct wined3d_renderbuffer_entry *entry, *entry2;
90 const struct wined3d_gl_info *gl_info;
91 struct wined3d_context *context;
92
93 context = context_acquire(surface->resource.device, NULL);
94 gl_info = context->gl_info;
95
96 if (surface->texture_name)
97 {
98 TRACE("Deleting texture %u.\n", surface->texture_name);
99#ifdef VBOX_WITH_WDDM
100 texture_gl_delete(surface->texture_name);
101#else
102 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
103#endif
104 }
105
106 if (surface->flags & SFLAG_PBO)
107 {
108 TRACE("Deleting PBO %u.\n", surface->pbo);
109 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
110 }
111
112 if (surface->rb_multisample)
113 {
114 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
115 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
116 }
117
118 if (surface->rb_resolved)
119 {
120 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
121 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
122 }
123
124 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
125 {
126 TRACE("Deleting renderbuffer %u.\n", entry->id);
127 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
128 HeapFree(GetProcessHeap(), 0, entry);
129 }
130
131 context_release(context);
132 }
133
134 if (surface->flags & SFLAG_DIBSECTION)
135 {
136 DeleteDC(surface->hDC);
137 DeleteObject(surface->dib.DIBsection);
138 surface->dib.bitmap_data = NULL;
139 surface->resource.allocatedMemory = NULL;
140 }
141
142 if (surface->flags & SFLAG_USERPTR)
143 wined3d_surface_set_mem(surface, NULL, 0);
144 if (surface->overlay_dest)
145 list_remove(&surface->overlay_entry);
146
147 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
148 {
149 list_remove(&overlay->overlay_entry);
150 overlay->overlay_dest = NULL;
151 }
152
153 resource_cleanup(&surface->resource);
154
155#ifdef VBOX_WITH_WDDM
156 /* @rodo: CHECK AND REMOVE : this should not be necessary anymore */
157 {
158 struct wined3d_device *device = surface->resource.device;
159 struct wined3d_context *context;
160 UINT i;
161 for (i = 0; i < device->context_count; ++i)
162 {
163 context = device->contexts[i];
164 /* pretty hacky, @todo: check if the context is acquired and re-acquire it with the new swapchain */
165 if (context->current_rt == surface)
166 {
167 Assert(0);
168 }
169 }
170 }
171#endif
172
173}
174
175void surface_update_draw_binding(struct wined3d_surface *surface)
176{
177 if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
178 surface->draw_binding = SFLAG_INDRAWABLE;
179 else if (surface->resource.multisample_type)
180 surface->draw_binding = SFLAG_INRB_MULTISAMPLE;
181 else
182 surface->draw_binding = SFLAG_INTEXTURE;
183}
184
185void surface_set_swapchain(struct wined3d_surface *surface, struct wined3d_swapchain *swapchain)
186{
187 TRACE("surface %p, swapchain %p.\n", surface, swapchain);
188
189 if (swapchain)
190 {
191 surface->get_drawable_size = get_drawable_size_swapchain;
192 }
193 else
194 {
195 switch (wined3d_settings.offscreen_rendering_mode)
196 {
197 case ORM_FBO:
198 surface->get_drawable_size = get_drawable_size_fbo;
199 break;
200
201 case ORM_BACKBUFFER:
202 surface->get_drawable_size = get_drawable_size_backbuffer;
203 break;
204
205 default:
206 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
207 return;
208 }
209 }
210
211 surface->swapchain = swapchain;
212 surface_update_draw_binding(surface);
213}
214
215void surface_set_container(struct wined3d_surface *surface, struct wined3d_texture *container)
216{
217 TRACE("surface %p, container %p.\n", surface, container);
218
219 if (!surface->swapchain)
220 {
221 switch (wined3d_settings.offscreen_rendering_mode)
222 {
223 case ORM_FBO:
224 surface->get_drawable_size = get_drawable_size_fbo;
225 break;
226
227 case ORM_BACKBUFFER:
228 surface->get_drawable_size = get_drawable_size_backbuffer;
229 break;
230
231 default:
232 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
233 return;
234 }
235 }
236
237 surface->container = container;
238 surface_update_draw_binding(surface);
239}
240
241struct blt_info
242{
243 GLenum binding;
244 GLenum bind_target;
245 enum tex_types tex_type;
246 GLfloat coords[4][3];
247};
248
249struct float_rect
250{
251 float l;
252 float t;
253 float r;
254 float b;
255};
256
257static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
258{
259 f->l = ((r->left * 2.0f) / w) - 1.0f;
260 f->t = ((r->top * 2.0f) / h) - 1.0f;
261 f->r = ((r->right * 2.0f) / w) - 1.0f;
262 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
263}
264
265static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
266{
267 GLfloat (*coords)[3] = info->coords;
268 struct float_rect f;
269
270 switch (target)
271 {
272 default:
273 FIXME("Unsupported texture target %#x\n", target);
274 /* Fall back to GL_TEXTURE_2D */
275 case GL_TEXTURE_2D:
276 info->binding = GL_TEXTURE_BINDING_2D;
277 info->bind_target = GL_TEXTURE_2D;
278 info->tex_type = tex_2d;
279 coords[0][0] = (float)rect->left / w;
280 coords[0][1] = (float)rect->top / h;
281 coords[0][2] = 0.0f;
282
283 coords[1][0] = (float)rect->right / w;
284 coords[1][1] = (float)rect->top / h;
285 coords[1][2] = 0.0f;
286
287 coords[2][0] = (float)rect->left / w;
288 coords[2][1] = (float)rect->bottom / h;
289 coords[2][2] = 0.0f;
290
291 coords[3][0] = (float)rect->right / w;
292 coords[3][1] = (float)rect->bottom / h;
293 coords[3][2] = 0.0f;
294 break;
295
296 case GL_TEXTURE_RECTANGLE_ARB:
297 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
298 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
299 info->tex_type = tex_rect;
300 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
301 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
302 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
303 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
304 break;
305
306 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
307 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
308 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
309 info->tex_type = tex_cube;
310 cube_coords_float(rect, w, h, &f);
311
312 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
313 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
314 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
315 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
316 break;
317
318 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
319 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
320 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
321 info->tex_type = tex_cube;
322 cube_coords_float(rect, w, h, &f);
323
324 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
325 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
326 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
327 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
328 break;
329
330 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
331 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
332 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
333 info->tex_type = tex_cube;
334 cube_coords_float(rect, w, h, &f);
335
336 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
337 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
338 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
339 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
340 break;
341
342 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
343 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
344 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
345 info->tex_type = tex_cube;
346 cube_coords_float(rect, w, h, &f);
347
348 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
349 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
350 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
351 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
352 break;
353
354 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
355 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
356 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
357 info->tex_type = tex_cube;
358 cube_coords_float(rect, w, h, &f);
359
360 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
361 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
362 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
363 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
364 break;
365
366 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
367 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
368 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
369 info->tex_type = tex_cube;
370 cube_coords_float(rect, w, h, &f);
371
372 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
373 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
374 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
375 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
376 break;
377 }
378}
379
380static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
381{
382 if (rect_in)
383 *rect_out = *rect_in;
384 else
385 {
386 rect_out->left = 0;
387 rect_out->top = 0;
388 rect_out->right = surface->resource.width;
389 rect_out->bottom = surface->resource.height;
390 }
391}
392
393/* Context activation is done by the caller. */
394void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
395 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
396{
397 const struct wined3d_gl_info *gl_info = context->gl_info;
398 struct blt_info info;
399
400 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
401
402 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
403 checkGLcall("glEnable(bind_target)");
404
405 context_bind_texture(context, info.bind_target, src_surface->texture_name);
406
407 /* Filtering for StretchRect */
408 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
409 wined3d_gl_mag_filter(magLookup, filter));
410 checkGLcall("glTexParameteri");
411 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
412 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
413 checkGLcall("glTexParameteri");
414 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
415 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
416 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
417 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
418 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
419 checkGLcall("glTexEnvi");
420
421 /* Draw a quad */
422 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
423 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
424 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
425
426 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
427 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
428
429 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
430 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
431
432 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
433 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
434 gl_info->gl_ops.gl.p_glEnd();
435
436 /* Unbind the texture */
437 context_bind_texture(context, info.bind_target, 0);
438
439 /* We changed the filtering settings on the texture. Inform the
440 * container about this to get the filters reset properly next draw. */
441 if (src_surface->container)
442 {
443 struct wined3d_texture *texture = src_surface->container;
444 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
445 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
446 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
447 texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE;
448 }
449}
450
451/* Works correctly only for <= 4 bpp formats. */
452static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
453{
454 masks[0] = ((1 << format->red_size) - 1) << format->red_offset;
455 masks[1] = ((1 << format->green_size) - 1) << format->green_offset;
456 masks[2] = ((1 << format->blue_size) - 1) << format->blue_offset;
457}
458
459static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
460{
461 const struct wined3d_format *format = surface->resource.format;
462 SYSTEM_INFO sysInfo;
463 BITMAPINFO *b_info;
464 int extraline = 0;
465 DWORD *masks;
466
467 TRACE("surface %p.\n", surface);
468
469 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
470 {
471 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
472 return WINED3DERR_INVALIDCALL;
473 }
474
475 switch (format->byte_count)
476 {
477 case 2:
478 case 4:
479 /* Allocate extra space to store the RGB bit masks. */
480 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
481 break;
482
483 case 3:
484 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
485 break;
486
487 default:
488 /* Allocate extra space for a palette. */
489 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
490 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
491 break;
492 }
493
494 if (!b_info)
495 return E_OUTOFMEMORY;
496
497 /* Some applications access the surface in via DWORDs, and do not take
498 * the necessary care at the end of the surface. So we need at least
499 * 4 extra bytes at the end of the surface. Check against the page size,
500 * if the last page used for the surface has at least 4 spare bytes we're
501 * safe, otherwise add an extra line to the DIB section. */
502 GetSystemInfo(&sysInfo);
503 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
504 {
505 extraline = 1;
506 TRACE("Adding an extra line to the DIB section.\n");
507 }
508
509 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
510 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
511 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
512 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
513 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
514 * wined3d_surface_get_pitch(surface);
515 b_info->bmiHeader.biPlanes = 1;
516 b_info->bmiHeader.biBitCount = format->byte_count * 8;
517
518 b_info->bmiHeader.biXPelsPerMeter = 0;
519 b_info->bmiHeader.biYPelsPerMeter = 0;
520 b_info->bmiHeader.biClrUsed = 0;
521 b_info->bmiHeader.biClrImportant = 0;
522
523 /* Get the bit masks */
524 masks = (DWORD *)b_info->bmiColors;
525 switch (surface->resource.format->id)
526 {
527 case WINED3DFMT_B8G8R8_UNORM:
528 b_info->bmiHeader.biCompression = BI_RGB;
529 break;
530
531 case WINED3DFMT_B5G5R5X1_UNORM:
532 case WINED3DFMT_B5G5R5A1_UNORM:
533 case WINED3DFMT_B4G4R4A4_UNORM:
534 case WINED3DFMT_B4G4R4X4_UNORM:
535 case WINED3DFMT_B2G3R3_UNORM:
536 case WINED3DFMT_B2G3R3A8_UNORM:
537 case WINED3DFMT_R10G10B10A2_UNORM:
538 case WINED3DFMT_R8G8B8A8_UNORM:
539 case WINED3DFMT_R8G8B8X8_UNORM:
540 case WINED3DFMT_B10G10R10A2_UNORM:
541 case WINED3DFMT_B5G6R5_UNORM:
542 case WINED3DFMT_R16G16B16A16_UNORM:
543 b_info->bmiHeader.biCompression = BI_BITFIELDS;
544 get_color_masks(format, masks);
545 break;
546
547 default:
548 /* Don't know palette */
549 b_info->bmiHeader.biCompression = BI_RGB;
550 break;
551 }
552
553 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
554 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
555 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
556 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
557
558 if (!surface->dib.DIBsection)
559 {
560 ERR("Failed to create DIB section.\n");
561 HeapFree(GetProcessHeap(), 0, b_info);
562 return HRESULT_FROM_WIN32(GetLastError());
563 }
564
565 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
566 /* Copy the existing surface to the dib section. */
567 if (surface->resource.allocatedMemory)
568 {
569 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
570 surface->resource.height * wined3d_surface_get_pitch(surface));
571 }
572 else
573 {
574 /* This is to make maps read the GL texture although memory is allocated. */
575 surface->flags &= ~SFLAG_INSYSMEM;
576 }
577 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
578
579 HeapFree(GetProcessHeap(), 0, b_info);
580
581 /* Now allocate a DC. */
582 surface->hDC = CreateCompatibleDC(0);
583 SelectObject(surface->hDC, surface->dib.DIBsection);
584 TRACE("Using wined3d palette %p.\n", surface->palette);
585 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
586
587 surface->flags |= SFLAG_DIBSECTION;
588
589 return WINED3D_OK;
590}
591
592static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
593{
594 if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
595 return FALSE;
596 if (!(surface->flags & SFLAG_DYNLOCK))
597 return FALSE;
598 if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
599 return FALSE;
600 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
601 return FALSE;
602
603 return TRUE;
604}
605
606static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
607{
608 struct wined3d_context *context;
609 GLenum error;
610
611 context = context_acquire(surface->resource.device, NULL);
612
613 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
614 error = gl_info->gl_ops.gl.p_glGetError();
615 if (!surface->pbo || error != GL_NO_ERROR)
616 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
617
618 TRACE("Binding PBO %u.\n", surface->pbo);
619
620 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
621 checkGLcall("glBindBufferARB");
622
623 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
624 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
625 checkGLcall("glBufferDataARB");
626
627 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
628 checkGLcall("glBindBufferARB");
629
630 /* We don't need the system memory anymore and we can't even use it for PBOs. */
631 if (!(surface->flags & SFLAG_CLIENT))
632 {
633 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
634 surface->resource.heapMemory = NULL;
635 }
636 surface->resource.allocatedMemory = NULL;
637 surface->flags |= SFLAG_PBO;
638 context_release(context);
639}
640
641#ifdef VBOX_WITH_WDDM
642static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
643 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type);
644
645void surface_setup_location_onopen(struct wined3d_surface *surface)
646{
647 struct wined3d_device *device = surface->resource.device;
648 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
649 DWORD alloc_flag = SFLAG_ALLOCATED;
650// DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
651 enum wined3d_conversion_type convert;
652 struct wined3d_format format;
653
654
655 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
656 if (convert != WINED3D_CT_NONE || format.convert)
657 surface->flags |= SFLAG_CONVERTED;
658 else surface->flags &= ~SFLAG_CONVERTED;
659
660 if(surface->container)
661 {
662 struct wined3d_context *context = context_acquire(device, NULL);
663 pglChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface));
664 context_release(context);
665
666 }
667 /* else -> all should be already set in texture init,
668 * which actually calls the current routine for each of texture's surfaces
669 * for setting up their state */
670
671 surface->flags |= alloc_flag;
672 surface->texture_name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface);
673
674 surface_modify_location(surface, SFLAG_INTEXTURE, TRUE);
675}
676#endif
677
678static void surface_prepare_system_memory(struct wined3d_surface *surface)
679{
680 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
681
682 TRACE("surface %p.\n", surface);
683
684 if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
685 surface_load_pbo(surface, gl_info);
686 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
687 {
688 /* Whatever surface we have, make sure that there is memory allocated
689 * for the downloaded copy, or a PBO to map. */
690 if (!surface->resource.heapMemory)
691 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
692
693 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
694 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
695
696 if (surface->flags & SFLAG_INSYSMEM)
697 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
698 }
699}
700
701static void surface_evict_sysmem(struct wined3d_surface *surface)
702{
703 if (surface->resource.map_count || (surface->flags & SFLAG_DONOTFREE))
704 return;
705
706 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
707 surface->resource.allocatedMemory = NULL;
708 surface->resource.heapMemory = NULL;
709 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
710}
711
712/* Context activation is done by the caller. */
713static void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
714{
715 TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb);
716
717 if (surface->container)
718 {
719 struct wined3d_texture *texture = surface->container;
720
721 TRACE("Passing to container (%p).\n", texture);
722 texture->texture_ops->texture_bind(texture, context, srgb);
723 }
724 else
725 {
726 const struct wined3d_gl_info *gl_info = context->gl_info;
727
728 if (surface->texture_level)
729 {
730 ERR("Standalone surface %p is non-zero texture level %u.\n",
731 surface, surface->texture_level);
732 }
733
734 if (srgb)
735 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
736
737 if (!surface->texture_name)
738 {
739#ifdef VBOX_WITH_WDDM
740 if (VBOXSHRC_IS_SHARED_OPENED(surface))
741 {
742 struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
743 ERR("should not be here!");
744 surface->texture_name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface);
745 Assert(surface->texture_name);
746 pglChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, surface->texture_name);
747 }
748 else
749#endif
750 {
751 gl_info->gl_ops.gl.p_glGenTextures(1, &surface->texture_name);
752 checkGLcall("glGenTextures");
753
754 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
755
756 context_bind_texture(context, surface->texture_target, surface->texture_name);
757 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
758 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
759 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
760 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
761 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
762 checkGLcall("glTexParameteri");
763
764#ifdef VBOX_WITH_WDDM
765 if (VBOXSHRC_IS_SHARED(surface))
766 {
767 VBOXSHRC_SET_SHAREHANDLE(surface, surface->texture_name);
768 }
769#endif
770 }
771 }
772 else
773 {
774 context_bind_texture(context, surface->texture_target, surface->texture_name);
775 }
776
777 }
778}
779
780/* Context activation is done by the caller. */
781static void surface_bind_and_dirtify(struct wined3d_surface *surface,
782 struct wined3d_context *context, BOOL srgb)
783{
784 struct wined3d_device *device = surface->resource.device;
785 DWORD active_sampler;
786
787 /* We don't need a specific texture unit, but after binding the texture
788 * the current unit is dirty. Read the unit back instead of switching to
789 * 0, this avoids messing around with the state manager's GL states. The
790 * current texture unit should always be a valid one.
791 *
792 * To be more specific, this is tricky because we can implicitly be
793 * called from sampler() in state.c. This means we can't touch anything
794 * other than whatever happens to be the currently active texture, or we
795 * would risk marking already applied sampler states dirty again. */
796 active_sampler = device->rev_tex_unit_map[context->active_texture];
797
798#if 0 //def DEBUG_misha
799 {
800 GLint active_texture=GL_TEXTURE0_ARB;
801 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
802 Assert(active_texture - GL_TEXTURE0_ARB == context->active_texture);
803 }
804#endif
805
806 if (active_sampler != WINED3D_UNMAPPED_STAGE)
807 device_invalidate_state(device, STATE_SAMPLER(active_sampler));
808 surface_bind(surface, context, srgb);
809}
810
811static void surface_force_reload(struct wined3d_surface *surface)
812{
813 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
814}
815
816static void surface_release_client_storage(struct wined3d_surface *surface)
817{
818 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
819 const struct wined3d_gl_info *gl_info = context->gl_info;
820
821 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
822 if (surface->texture_name)
823 {
824 surface_bind_and_dirtify(surface, context, FALSE);
825 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
826 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
827 }
828 if (surface->texture_name_srgb)
829 {
830 surface_bind_and_dirtify(surface, context, TRUE);
831 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
832 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
833 }
834 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
835
836 context_release(context);
837
838 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
839 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
840 surface_force_reload(surface);
841}
842
843static HRESULT surface_private_setup(struct wined3d_surface *surface)
844{
845 /* TODO: Check against the maximum texture sizes supported by the video card. */
846 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
847 unsigned int pow2Width, pow2Height;
848
849 TRACE("surface %p.\n", surface);
850
851 surface->texture_name = 0;
852 surface->texture_target = GL_TEXTURE_2D;
853
854 /* Non-power2 support */
855 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
856 {
857 pow2Width = surface->resource.width;
858 pow2Height = surface->resource.height;
859 }
860 else
861 {
862 /* Find the nearest pow2 match */
863 pow2Width = pow2Height = 1;
864 while (pow2Width < surface->resource.width)
865 pow2Width <<= 1;
866 while (pow2Height < surface->resource.height)
867 pow2Height <<= 1;
868 }
869 surface->pow2Width = pow2Width;
870 surface->pow2Height = pow2Height;
871
872 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
873 {
874 /* TODO: Add support for non power two compressed textures. */
875 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
876 {
877 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
878 surface, surface->resource.width, surface->resource.height);
879 return WINED3DERR_NOTAVAILABLE;
880 }
881 }
882
883 if (pow2Width != surface->resource.width
884 || pow2Height != surface->resource.height)
885 {
886 surface->flags |= SFLAG_NONPOW2;
887 }
888
889 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
890 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
891 {
892 /* One of three options:
893 * 1: Do the same as we do with NPOT and scale the texture, (any
894 * texture ops would require the texture to be scaled which is
895 * potentially slow)
896 * 2: Set the texture to the maximum size (bad idea).
897 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
898 * 4: Create the surface, but allow it to be used only for DirectDraw
899 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
900 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
901 * the render target. */
902 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
903 {
904 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
905 return WINED3DERR_NOTAVAILABLE;
906 }
907
908 /* We should never use this surface in combination with OpenGL! */
909 TRACE("Creating an oversized surface: %ux%u.\n",
910 surface->pow2Width, surface->pow2Height);
911 }
912 else
913 {
914 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
915 * and EXT_PALETTED_TEXTURE is used in combination with texture
916 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
917 * EXT_PALETTED_TEXTURE doesn't work in combination with
918 * ARB_TEXTURE_RECTANGLE. */
919 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
920 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
921 && gl_info->supported[EXT_PALETTED_TEXTURE]
922 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
923 {
924 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
925 surface->pow2Width = surface->resource.width;
926 surface->pow2Height = surface->resource.height;
927 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
928 }
929 }
930
931 switch (wined3d_settings.offscreen_rendering_mode)
932 {
933 case ORM_FBO:
934 surface->get_drawable_size = get_drawable_size_fbo;
935 break;
936
937 case ORM_BACKBUFFER:
938 surface->get_drawable_size = get_drawable_size_backbuffer;
939 break;
940
941 default:
942 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
943 return WINED3DERR_INVALIDCALL;
944 }
945
946 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
947 surface->flags |= SFLAG_DISCARDED;
948
949 return WINED3D_OK;
950}
951
952static void surface_realize_palette(struct wined3d_surface *surface)
953{
954 struct wined3d_palette *palette = surface->palette;
955
956 TRACE("surface %p.\n", surface);
957
958 if (!palette) return;
959
960 if (surface->resource.format->id == WINED3DFMT_P8_UINT
961 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
962 {
963 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
964 {
965 /* Make sure the texture is up to date. This call doesn't do
966 * anything if the texture is already up to date. */
967 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
968
969 /* We want to force a palette refresh, so mark the drawable as not being up to date */
970 if (!surface_is_offscreen(surface))
971 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
972 }
973 else
974 {
975 if (!(surface->flags & SFLAG_INSYSMEM))
976 {
977 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
978 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
979 }
980 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
981 }
982 }
983
984 if (surface->flags & SFLAG_DIBSECTION)
985 {
986 RGBQUAD col[256];
987 unsigned int i;
988
989 TRACE("Updating the DC's palette.\n");
990
991 for (i = 0; i < 256; ++i)
992 {
993 col[i].rgbRed = palette->palents[i].peRed;
994 col[i].rgbGreen = palette->palents[i].peGreen;
995 col[i].rgbBlue = palette->palents[i].peBlue;
996 col[i].rgbReserved = 0;
997 }
998 SetDIBColorTable(surface->hDC, 0, 256, col);
999 }
1000
1001 /* Propagate the changes to the drawable when we have a palette. */
1002 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1003 surface_load_location(surface, surface->draw_binding, NULL);
1004}
1005
1006static HRESULT surface_draw_overlay(struct wined3d_surface *surface)
1007{
1008 HRESULT hr;
1009
1010 /* If there's no destination surface there is nothing to do. */
1011 if (!surface->overlay_dest)
1012 return WINED3D_OK;
1013
1014 /* Blt calls ModifyLocation on the dest surface, which in turn calls
1015 * DrawOverlay to update the overlay. Prevent an endless recursion. */
1016 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
1017 return WINED3D_OK;
1018
1019 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
1020 hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface,
1021 &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR);
1022 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
1023
1024 return hr;
1025}
1026
1027static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
1028{
1029 struct wined3d_device *device = surface->resource.device;
1030 const RECT *pass_rect = rect;
1031
1032 TRACE("surface %p, rect %s, flags %#x.\n",
1033 surface, wine_dbgstr_rect(rect), flags);
1034
1035 if (flags & WINED3D_MAP_DISCARD)
1036 {
1037 TRACE("WINED3D_MAP_DISCARD flag passed, marking SYSMEM as up to date.\n");
1038 surface_prepare_system_memory(surface);
1039 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1040 }
1041 else
1042 {
1043 if (surface->resource.usage & WINED3DUSAGE_DYNAMIC)
1044 WARN_(d3d_perf)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
1045
1046 /* surface_load_location() does not check if the rectangle specifies
1047 * the full surface. Most callers don't need that, so do it here. */
1048 if (rect && !rect->top && !rect->left
1049 && rect->right == surface->resource.width
1050 && rect->bottom == surface->resource.height)
1051 pass_rect = NULL;
1052 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
1053 }
1054
1055 if (surface->flags & SFLAG_PBO)
1056 {
1057 const struct wined3d_gl_info *gl_info;
1058 struct wined3d_context *context;
1059
1060 context = context_acquire(device, NULL);
1061 gl_info = context->gl_info;
1062
1063 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1064 checkGLcall("glBindBufferARB");
1065
1066 /* This shouldn't happen but could occur if some other function
1067 * didn't handle the PBO properly. */
1068 if (surface->resource.allocatedMemory)
1069 ERR("The surface already has PBO memory allocated.\n");
1070
1071 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1072 checkGLcall("glMapBufferARB");
1073
1074 /* Make sure the PBO isn't set anymore in order not to break non-PBO
1075 * calls. */
1076 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1077 checkGLcall("glBindBufferARB");
1078
1079 context_release(context);
1080 }
1081
1082 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
1083 {
1084 if (!rect)
1085 surface_add_dirty_rect(surface, NULL);
1086 else
1087 {
1088 struct wined3d_box b;
1089
1090 b.left = rect->left;
1091 b.top = rect->top;
1092 b.right = rect->right;
1093 b.bottom = rect->bottom;
1094 b.front = 0;
1095 b.back = 1;
1096 surface_add_dirty_rect(surface, &b);
1097 }
1098 }
1099}
1100
1101static void surface_unmap(struct wined3d_surface *surface)
1102{
1103 struct wined3d_device *device = surface->resource.device;
1104 BOOL fullsurface;
1105
1106 TRACE("surface %p.\n", surface);
1107
1108 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
1109
1110 if (surface->flags & SFLAG_PBO)
1111 {
1112 const struct wined3d_gl_info *gl_info;
1113 struct wined3d_context *context;
1114
1115 TRACE("Freeing PBO memory.\n");
1116
1117 context = context_acquire(device, NULL);
1118 gl_info = context->gl_info;
1119
1120 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1121 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1122 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1123 checkGLcall("glUnmapBufferARB");
1124 context_release(context);
1125
1126 surface->resource.allocatedMemory = NULL;
1127 }
1128
1129 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1130
1131 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
1132 {
1133 TRACE("Not dirtified, nothing to do.\n");
1134 goto done;
1135 }
1136
1137 if (surface->swapchain && surface->swapchain->front_buffer == surface)
1138 {
1139 if (!surface->dirtyRect.left && !surface->dirtyRect.top
1140 && surface->dirtyRect.right == surface->resource.width
1141 && surface->dirtyRect.bottom == surface->resource.height)
1142 {
1143 fullsurface = TRUE;
1144 }
1145 else
1146 {
1147 /* TODO: Proper partial rectangle tracking. */
1148 fullsurface = FALSE;
1149 surface->flags |= SFLAG_INSYSMEM;
1150 }
1151
1152 surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect);
1153
1154 /* Partial rectangle tracking is not commonly implemented, it is only
1155 * done for render targets. INSYSMEM was set before to tell
1156 * surface_load_location() where to read the rectangle from.
1157 * Indrawable is set because all modifications from the partial
1158 * sysmem copy are written back to the drawable, thus the surface is
1159 * merged again in the drawable. The sysmem copy is not fully up to
1160 * date because only a subrectangle was read in Map(). */
1161 if (!fullsurface)
1162 {
1163 surface_modify_location(surface, surface->draw_binding, TRUE);
1164 surface_evict_sysmem(surface);
1165 }
1166
1167 surface->dirtyRect.left = surface->resource.width;
1168 surface->dirtyRect.top = surface->resource.height;
1169 surface->dirtyRect.right = 0;
1170 surface->dirtyRect.bottom = 0;
1171 }
1172 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1173 {
1174 FIXME("Depth / stencil buffer locking is not implemented.\n");
1175 }
1176
1177done:
1178 /* Overlays have to be redrawn manually after changes with the GL implementation */
1179 if (surface->overlay_dest)
1180 surface_draw_overlay(surface);
1181}
1182
1183static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
1184{
1185 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
1186 return FALSE;
1187 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
1188 return FALSE;
1189 return TRUE;
1190}
1191
1192static void surface_depth_blt_fbo(const struct wined3d_device *device,
1193 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
1194 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
1195{
1196 const struct wined3d_gl_info *gl_info;
1197 struct wined3d_context *context;
1198 DWORD src_mask, dst_mask;
1199 GLbitfield gl_mask;
1200
1201 TRACE("device %p\n", device);
1202 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1203 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect));
1204 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1205 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect));
1206
1207 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1208 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1209
1210 if (src_mask != dst_mask)
1211 {
1212 ERR("Incompatible formats %s and %s.\n",
1213 debug_d3dformat(src_surface->resource.format->id),
1214 debug_d3dformat(dst_surface->resource.format->id));
1215 return;
1216 }
1217
1218 if (!src_mask)
1219 {
1220 ERR("Not a depth / stencil format: %s.\n",
1221 debug_d3dformat(src_surface->resource.format->id));
1222 return;
1223 }
1224
1225 gl_mask = 0;
1226 if (src_mask & WINED3DFMT_FLAG_DEPTH)
1227 gl_mask |= GL_DEPTH_BUFFER_BIT;
1228 if (src_mask & WINED3DFMT_FLAG_STENCIL)
1229 gl_mask |= GL_STENCIL_BUFFER_BIT;
1230
1231 /* Make sure the locations are up-to-date. Loading the destination
1232 * surface isn't required if the entire surface is overwritten. */
1233 surface_load_location(src_surface, src_location, NULL);
1234 if (!surface_is_full_rect(dst_surface, dst_rect))
1235 surface_load_location(dst_surface, dst_location, NULL);
1236
1237 context = context_acquire(device, NULL);
1238 if (!context->valid)
1239 {
1240 context_release(context);
1241 WARN("Invalid context, skipping blit.\n");
1242 return;
1243 }
1244
1245 gl_info = context->gl_info;
1246
1247 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
1248 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1249
1250 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
1251 context_set_draw_buffer(context, GL_NONE);
1252 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1253 context_invalidate_state(context, STATE_FRAMEBUFFER);
1254
1255 if (gl_mask & GL_DEPTH_BUFFER_BIT)
1256 {
1257 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
1258 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
1259 }
1260 if (gl_mask & GL_STENCIL_BUFFER_BIT)
1261 {
1262 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
1263 {
1264 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1265 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
1266 }
1267 gl_info->gl_ops.gl.p_glStencilMask(~0U);
1268 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1269 }
1270
1271 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1272 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1273
1274 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
1275 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
1276 checkGLcall("glBlitFramebuffer()");
1277
1278 if (wined3d_settings.strict_draw_ordering)
1279 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
1280
1281 context_release(context);
1282}
1283
1284/* Blit between surface locations. Onscreen on different swapchains is not supported.
1285 * Depth / stencil is not supported. */
1286static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
1287 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
1288 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
1289{
1290 const struct wined3d_gl_info *gl_info;
1291 struct wined3d_context *context;
1292 RECT src_rect, dst_rect;
1293 GLenum gl_filter;
1294 GLenum buffer;
1295
1296 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
1297 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1298 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
1299 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1300 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
1301
1302 src_rect = *src_rect_in;
1303 dst_rect = *dst_rect_in;
1304
1305 switch (filter)
1306 {
1307 case WINED3D_TEXF_LINEAR:
1308 gl_filter = GL_LINEAR;
1309 break;
1310
1311 default:
1312 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
1313 case WINED3D_TEXF_NONE:
1314 case WINED3D_TEXF_POINT:
1315 gl_filter = GL_NEAREST;
1316 break;
1317 }
1318
1319 /* Resolve the source surface first if needed. */
1320 if (src_location == SFLAG_INRB_MULTISAMPLE
1321 && (src_surface->resource.format->id != dst_surface->resource.format->id
1322 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
1323 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
1324 src_location = SFLAG_INRB_RESOLVED;
1325
1326 /* Make sure the locations are up-to-date. Loading the destination
1327 * surface isn't required if the entire surface is overwritten. (And is
1328 * in fact harmful if we're being called by surface_load_location() with
1329 * the purpose of loading the destination surface.) */
1330 surface_load_location(src_surface, src_location, NULL);
1331 if (!surface_is_full_rect(dst_surface, &dst_rect))
1332 surface_load_location(dst_surface, dst_location, NULL);
1333
1334 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
1335 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
1336 else context = context_acquire(device, NULL);
1337
1338 if (!context->valid)
1339 {
1340 context_release(context);
1341 WARN("Invalid context, skipping blit.\n");
1342 return;
1343 }
1344
1345 gl_info = context->gl_info;
1346
1347 if (src_location == SFLAG_INDRAWABLE)
1348 {
1349 TRACE("Source surface %p is onscreen.\n", src_surface);
1350 buffer = surface_get_gl_buffer(src_surface);
1351#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1352 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
1353#else
1354 surface_translate_drawable_coords(src_surface, context->swapchain->win_handle, &src_rect);
1355#endif
1356 }
1357 else
1358 {
1359 TRACE("Source surface %p is offscreen.\n", src_surface);
1360 buffer = GL_COLOR_ATTACHMENT0;
1361 }
1362
1363 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
1364 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1365 checkGLcall("glReadBuffer()");
1366 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1367
1368 if (dst_location == SFLAG_INDRAWABLE)
1369 {
1370 TRACE("Destination surface %p is onscreen.\n", dst_surface);
1371 buffer = surface_get_gl_buffer(dst_surface);
1372#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1373 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
1374#else
1375 surface_translate_drawable_coords(dst_surface, context->swapchain->win_handle, &dst_rect);
1376#endif
1377 }
1378 else
1379 {
1380 TRACE("Destination surface %p is offscreen.\n", dst_surface);
1381 buffer = GL_COLOR_ATTACHMENT0;
1382 }
1383
1384 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
1385 context_set_draw_buffer(context, buffer);
1386 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1387 context_invalidate_state(context, STATE_FRAMEBUFFER);
1388
1389 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1390 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1391 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1392 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1393 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1394
1395 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1396 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1397
1398 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1399 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1400 checkGLcall("glBlitFramebuffer()");
1401
1402 if (wined3d_settings.strict_draw_ordering
1403 || (dst_location == SFLAG_INDRAWABLE
1404 && dst_surface->swapchain->front_buffer == dst_surface))
1405 gl_info->gl_ops.gl.p_glFlush();
1406
1407 context_release(context);
1408}
1409
1410static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1411 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1412 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1413{
1414 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1415 return FALSE;
1416
1417 /* Source and/or destination need to be on the GL side */
1418 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1419 return FALSE;
1420
1421 switch (blit_op)
1422 {
1423 case WINED3D_BLIT_OP_COLOR_BLIT:
1424 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1425 return FALSE;
1426 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1427 return FALSE;
1428 break;
1429
1430 case WINED3D_BLIT_OP_DEPTH_BLIT:
1431 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1432 return FALSE;
1433 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1434 return FALSE;
1435 break;
1436
1437 default:
1438 return FALSE;
1439 }
1440
1441 if (!(src_format->id == dst_format->id
1442 || (is_identity_fixup(src_format->color_fixup)
1443 && is_identity_fixup(dst_format->color_fixup))))
1444 return FALSE;
1445
1446 return TRUE;
1447}
1448
1449/* This function checks if the primary render target uses the 8bit paletted format. */
1450static BOOL primary_render_target_is_p8(const struct wined3d_device *device)
1451{
1452 if (device->fb.render_targets && device->fb.render_targets[0])
1453 {
1454 const struct wined3d_surface *render_target = device->fb.render_targets[0];
1455 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1456 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1457 return TRUE;
1458 }
1459 return FALSE;
1460}
1461
1462static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
1463 DWORD color, struct wined3d_color *float_color)
1464{
1465 const struct wined3d_format *format = surface->resource.format;
1466 const struct wined3d_device *device = surface->resource.device;
1467
1468 switch (format->id)
1469 {
1470 case WINED3DFMT_P8_UINT:
1471 if (surface->palette)
1472 {
1473 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1474 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1475 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1476 }
1477 else
1478 {
1479 float_color->r = 0.0f;
1480 float_color->g = 0.0f;
1481 float_color->b = 0.0f;
1482 }
1483 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1484 break;
1485
1486 case WINED3DFMT_B5G6R5_UNORM:
1487 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1488 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1489 float_color->b = (color & 0x1f) / 31.0f;
1490 float_color->a = 1.0f;
1491 break;
1492
1493 case WINED3DFMT_B8G8R8_UNORM:
1494 case WINED3DFMT_B8G8R8X8_UNORM:
1495 float_color->r = D3DCOLOR_R(color);
1496 float_color->g = D3DCOLOR_G(color);
1497 float_color->b = D3DCOLOR_B(color);
1498 float_color->a = 1.0f;
1499 break;
1500
1501 case WINED3DFMT_B8G8R8A8_UNORM:
1502 float_color->r = D3DCOLOR_R(color);
1503 float_color->g = D3DCOLOR_G(color);
1504 float_color->b = D3DCOLOR_B(color);
1505 float_color->a = D3DCOLOR_A(color);
1506 break;
1507
1508 default:
1509 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1510 return FALSE;
1511 }
1512
1513 return TRUE;
1514}
1515
1516static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1517{
1518 const struct wined3d_format *format = surface->resource.format;
1519
1520 switch (format->id)
1521 {
1522 case WINED3DFMT_S1_UINT_D15_UNORM:
1523 *float_depth = depth / (float)0x00007fff;
1524 break;
1525
1526 case WINED3DFMT_D16_UNORM:
1527 *float_depth = depth / (float)0x0000ffff;
1528 break;
1529
1530 case WINED3DFMT_D24_UNORM_S8_UINT:
1531 case WINED3DFMT_X8D24_UNORM:
1532 *float_depth = depth / (float)0x00ffffff;
1533 break;
1534
1535 case WINED3DFMT_D32_UNORM:
1536 *float_depth = depth / (float)0xffffffff;
1537 break;
1538
1539 default:
1540 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1541 return FALSE;
1542 }
1543
1544 return TRUE;
1545}
1546
1547/* Do not call while under the GL lock. */
1548static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1549{
1550 const struct wined3d_resource *resource = &surface->resource;
1551 struct wined3d_device *device = resource->device;
1552 const struct blit_shader *blitter;
1553
1554 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1555 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1556 if (!blitter)
1557 {
1558 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1559 return WINED3DERR_INVALIDCALL;
1560 }
1561
1562 return blitter->depth_fill(device, surface, rect, depth);
1563}
1564
1565static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
1566 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
1567{
1568 struct wined3d_device *device = src_surface->resource.device;
1569
1570 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1571 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1572 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1573 return WINED3DERR_INVALIDCALL;
1574
1575 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
1576
1577 surface_modify_ds_location(dst_surface, dst_location,
1578 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1579
1580 return WINED3D_OK;
1581}
1582
1583/* Do not call while under the GL lock. */
1584HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
1585 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
1586 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
1587{
1588 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1589 struct wined3d_device *device = dst_surface->resource.device;
1590 DWORD src_ds_flags, dst_ds_flags;
1591 RECT src_rect, dst_rect;
1592 BOOL scale, convert;
1593#ifdef VBOX_WITH_WDDM
1594 HRESULT hr = WINED3D_OK;
1595#endif
1596
1597 static const DWORD simple_blit = WINEDDBLT_ASYNC
1598 | WINEDDBLT_COLORFILL
1599 | WINEDDBLT_WAIT
1600 | WINEDDBLT_DEPTHFILL
1601 | WINEDDBLT_DONOTWAIT;
1602
1603 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1604 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
1605 flags, fx, debug_d3dtexturefiltertype(filter));
1606 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
1607
1608 if (fx)
1609 {
1610 TRACE("dwSize %#x.\n", fx->dwSize);
1611 TRACE("dwDDFX %#x.\n", fx->dwDDFX);
1612 TRACE("dwROP %#x.\n", fx->dwROP);
1613 TRACE("dwDDROP %#x.\n", fx->dwDDROP);
1614 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
1615 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
1616 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
1617 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
1618 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
1619 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
1620 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
1621 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
1622 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
1623 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
1624 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
1625 TRACE("dwReserved %#x.\n", fx->dwReserved);
1626 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
1627 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
1628 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
1629 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
1630 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
1631 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1632 fx->ddckDestColorkey.color_space_low_value,
1633 fx->ddckDestColorkey.color_space_high_value);
1634 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1635 fx->ddckSrcColorkey.color_space_low_value,
1636 fx->ddckSrcColorkey.color_space_high_value);
1637 }
1638
1639 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
1640 {
1641 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1642 return WINEDDERR_SURFACEBUSY;
1643 }
1644
1645 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
1646
1647 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
1648 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
1649 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
1650 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
1651 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
1652 {
1653 WARN("The application gave us a bad destination rectangle.\n");
1654 return WINEDDERR_INVALIDRECT;
1655 }
1656
1657 if (src_surface)
1658 {
1659 surface_get_rect(src_surface, src_rect_in, &src_rect);
1660
1661 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
1662 || src_rect.left > src_surface->resource.width || src_rect.left < 0
1663 || src_rect.top > src_surface->resource.height || src_rect.top < 0
1664 || src_rect.right > src_surface->resource.width || src_rect.right < 0
1665 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
1666 {
1667 WARN("Application gave us bad source rectangle for Blt.\n");
1668 return WINEDDERR_INVALIDRECT;
1669 }
1670 }
1671 else
1672 {
1673 memset(&src_rect, 0, sizeof(src_rect));
1674 }
1675
1676#ifdef VBOX_WITH_WDDM
1677 surface_shrc_lock(dst_surface);
1678 if (src_surface) surface_shrc_lock(src_surface);
1679
1680 /* once we've done locking, we should do unlock on exit,
1681 * do goto post_process instead of return below! */
1682#endif
1683
1684 if (!fx || !(fx->dwDDFX))
1685 flags &= ~WINEDDBLT_DDFX;
1686
1687 if (flags & WINEDDBLT_WAIT)
1688 flags &= ~WINEDDBLT_WAIT;
1689
1690 if (flags & WINEDDBLT_ASYNC)
1691 {
1692 static unsigned int once;
1693
1694 if (!once++)
1695 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1696 flags &= ~WINEDDBLT_ASYNC;
1697 }
1698
1699 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1700 if (flags & WINEDDBLT_DONOTWAIT)
1701 {
1702 static unsigned int once;
1703
1704 if (!once++)
1705 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1706 flags &= ~WINEDDBLT_DONOTWAIT;
1707 }
1708
1709 if (!device->d3d_initialized)
1710 {
1711 WARN("D3D not initialized, using fallback.\n");
1712 goto cpu;
1713 }
1714
1715 /* We want to avoid invalidating the sysmem location for converted
1716 * surfaces, since otherwise we'd have to convert the data back when
1717 * locking them. */
1718 if (dst_surface->flags & SFLAG_CONVERTED)
1719 {
1720 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
1721#ifndef VBOX_WITH_WDDM
1722 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1723#else
1724 hr = surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1725 goto post_process;
1726#endif
1727
1728 }
1729
1730 if (flags & ~simple_blit)
1731 {
1732 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
1733 goto fallback;
1734 }
1735
1736 if (src_surface)
1737 src_swapchain = src_surface->swapchain;
1738 else
1739 src_swapchain = NULL;
1740
1741 dst_swapchain = dst_surface->swapchain;
1742
1743 /* This isn't strictly needed. FBO blits for example could deal with
1744 * cross-swapchain blits by first downloading the source to a texture
1745 * before switching to the destination context. We just have this here to
1746 * not have to deal with the issue, since cross-swapchain blits should be
1747 * rare. */
1748 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
1749 {
1750 FIXME("Using fallback for cross-swapchain blit.\n");
1751 goto fallback;
1752 }
1753
1754 scale = src_surface
1755 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
1756 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
1757 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
1758
1759 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1760 if (src_surface)
1761 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1762 else
1763 src_ds_flags = 0;
1764
1765 if (src_ds_flags || dst_ds_flags)
1766 {
1767 if (flags & WINEDDBLT_DEPTHFILL)
1768 {
1769 float depth;
1770
1771 TRACE("Depth fill.\n");
1772
1773 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
1774#ifndef VBOX_WITH_WDDM
1775 return WINED3DERR_INVALIDCALL;
1776#else
1777 {
1778 hr = WINED3DERR_INVALIDCALL;
1779 goto post_process;
1780 }
1781#endif
1782
1783 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
1784#ifndef VBOX_WITH_WDDM
1785 return WINED3D_OK;
1786#else
1787 {
1788 hr = WINED3D_OK;
1789 goto post_process;
1790 }
1791#endif
1792 }
1793 else
1794 {
1795 if (src_ds_flags != dst_ds_flags)
1796 {
1797 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1798#ifndef VBOX_WITH_WDDM
1799 return WINED3DERR_INVALIDCALL;
1800#else
1801 hr = WINED3D_OK;
1802 goto post_process;
1803#endif
1804 }
1805
1806 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->draw_binding, &src_rect,
1807 dst_surface, dst_surface->draw_binding, &dst_rect)))
1808#ifndef VBOX_WITH_WDDM
1809 return WINED3D_OK;
1810#else
1811 {
1812 hr = WINED3D_OK;
1813 goto post_process;
1814 }
1815#endif
1816 }
1817 }
1818 else
1819 {
1820 /* In principle this would apply to depth blits as well, but we don't
1821 * implement those in the CPU blitter at the moment. */
1822 if ((dst_surface->flags & SFLAG_INSYSMEM)
1823 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM)))
1824 {
1825#ifdef DEBUG_misha
1826 /* if below condition is not specified, i.e. both surfaces are in tecxture locations,
1827 * we would perhaps need to fallback to tex->tex hw blitting */
1828 Assert(!(dst_surface->flags & SFLAG_INTEXTURE) ||
1829 !src_surface || !(src_surface->flags & SFLAG_INTEXTURE));
1830#endif
1831 if (scale)
1832 TRACE("Not doing sysmem blit because of scaling.\n");
1833 else if (convert)
1834 TRACE("Not doing sysmem blit because of format conversion.\n");
1835 else
1836#ifndef VBOX_WITH_WDDM
1837 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1838#else
1839 {
1840 hr = surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1841 goto post_process;
1842 }
1843#endif
1844
1845 }
1846
1847 if (flags & WINEDDBLT_COLORFILL)
1848 {
1849 struct wined3d_color color;
1850
1851 TRACE("Color fill.\n");
1852
1853 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
1854 goto fallback;
1855
1856 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
1857#ifndef VBOX_WITH_WDDM
1858 return WINED3D_OK;
1859#else
1860 {
1861 hr = WINED3D_OK;
1862 goto post_process;
1863 }
1864#endif
1865 }
1866 else
1867 {
1868 TRACE("Color blit.\n");
1869
1870 /* Upload */
1871 if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM))
1872 {
1873 if (scale)
1874 TRACE("Not doing upload because of scaling.\n");
1875 else if (convert)
1876 TRACE("Not doing upload because of format conversion.\n");
1877 else
1878 {
1879 POINT dst_point = {dst_rect.left, dst_rect.top};
1880
1881 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
1882 {
1883 if (!surface_is_offscreen(dst_surface))
1884 surface_load_location(dst_surface, dst_surface->draw_binding, NULL);
1885#ifndef VBOX_WITH_WDDM
1886 return WINED3D_OK;
1887#else
1888 hr = WINED3D_OK;
1889 goto post_process;
1890#endif
1891 }
1892 }
1893 }
1894
1895 /* Use present for back -> front blits. The idea behind this is
1896 * that present is potentially faster than a blit, in particular
1897 * when FBO blits aren't available. Some ddraw applications like
1898 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1899 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1900 * applications can't blit directly to the frontbuffer. */
1901 if (dst_swapchain && dst_swapchain->back_buffers
1902 && dst_surface == dst_swapchain->front_buffer
1903 && src_surface == dst_swapchain->back_buffers[0])
1904 {
1905 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
1906
1907 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1908
1909 /* Set the swap effect to COPY, we don't want the backbuffer
1910 * to become undefined. */
1911 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
1912 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
1913 dst_swapchain->desc.swap_effect = swap_effect;
1914
1915#ifndef VBOX_WITH_WDDM
1916 return WINED3D_OK;
1917#else
1918 hr = WINED3D_OK;
1919 goto post_process;
1920#endif
1921 }
1922
1923 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1924 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1925 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1926 {
1927 TRACE("Using FBO blit.\n");
1928
1929 surface_blt_fbo(device, filter,
1930 src_surface, src_surface->draw_binding, &src_rect,
1931 dst_surface, dst_surface->draw_binding, &dst_rect);
1932 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
1933#ifndef VBOX_WITH_WDDM
1934 return WINED3D_OK;
1935#else
1936 hr = WINED3D_OK;
1937 goto post_process;
1938#endif
1939 }
1940
1941 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1942 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1943 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1944 {
1945 TRACE("Using arbfp blit.\n");
1946
1947 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
1948#ifndef VBOX_WITH_WDDM
1949 return WINED3D_OK;
1950#else
1951 {
1952 hr = WINED3D_OK;
1953 goto post_process;
1954 }
1955#endif
1956 }
1957 }
1958 }
1959
1960fallback:
1961
1962#ifdef DEBUG_misha
1963 /* test ! */
1964 Assert(0);
1965#endif
1966 /* Special cases for render targets. */
1967 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1968 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
1969 {
1970 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect,
1971 src_surface, &src_rect, flags, fx, filter)))
1972#ifndef VBOX_WITH_WDDM
1973 return WINED3D_OK;
1974#else
1975 {
1976 hr = WINED3D_OK;
1977 goto post_process;
1978 }
1979#endif
1980 }
1981
1982cpu:
1983
1984#ifdef DEBUG_misha
1985 /* test ! */
1986 Assert(0);
1987#endif
1988
1989
1990 /* For the rest call the X11 surface implementation. For render targets
1991 * this should be implemented OpenGL accelerated in BltOverride, other
1992 * blits are rather rare. */
1993#ifndef VBOX_WITH_WDDM
1994 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1995#else
1996 hr = surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1997 goto post_process;
1998#endif
1999
2000#ifdef VBOX_WITH_WDDM
2001post_process:
2002 surface_shrc_unlock(dst_surface);
2003 if (src_surface) surface_shrc_unlock(src_surface);
2004 return hr;
2005#endif
2006}
2007
2008HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
2009 struct wined3d_surface *render_target)
2010{
2011 TRACE("surface %p, render_target %p.\n", surface, render_target);
2012
2013 /* TODO: Check surface sizes, pools, etc. */
2014
2015 if (render_target->resource.multisample_type)
2016 return WINED3DERR_INVALIDCALL;
2017
2018 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
2019}
2020
2021/* Context activation is done by the caller. */
2022static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2023{
2024 if (surface->flags & SFLAG_DIBSECTION)
2025 {
2026 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2027 }
2028 else
2029 {
2030 if (!surface->resource.heapMemory)
2031 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
2032 else if (!(surface->flags & SFLAG_CLIENT))
2033 ERR("Surface %p has heapMemory %p and flags %#x.\n",
2034 surface, surface->resource.heapMemory, surface->flags);
2035
2036 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2037 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2038 }
2039
2040 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
2041 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
2042 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
2043 surface->resource.size, surface->resource.allocatedMemory));
2044 checkGLcall("glGetBufferSubDataARB");
2045 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
2046 checkGLcall("glDeleteBuffersARB");
2047
2048 surface->pbo = 0;
2049 surface->flags &= ~SFLAG_PBO;
2050}
2051
2052static BOOL surface_init_sysmem(struct wined3d_surface *surface)
2053{
2054 if (!surface->resource.allocatedMemory)
2055 {
2056 if (!surface->resource.heapMemory)
2057 {
2058 if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2059 surface->resource.size + RESOURCE_ALIGNMENT)))
2060 {
2061 ERR("Failed to allocate memory.\n");
2062 return FALSE;
2063 }
2064 }
2065 else if (!(surface->flags & SFLAG_CLIENT))
2066 {
2067 ERR("Surface %p has heapMemory %p and flags %#x.\n",
2068 surface, surface->resource.heapMemory, surface->flags);
2069 }
2070
2071 surface->resource.allocatedMemory =
2072 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2073 }
2074 else
2075 {
2076 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
2077 }
2078
2079 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2080
2081 return TRUE;
2082}
2083
2084/* Do not call while under the GL lock. */
2085static void surface_unload(struct wined3d_resource *resource)
2086{
2087 struct wined3d_surface *surface = surface_from_resource(resource);
2088 struct wined3d_renderbuffer_entry *entry, *entry2;
2089 struct wined3d_device *device = resource->device;
2090 const struct wined3d_gl_info *gl_info;
2091 struct wined3d_context *context;
2092
2093 TRACE("surface %p.\n", surface);
2094
2095 if (resource->pool == WINED3D_POOL_DEFAULT)
2096 {
2097 /* Default pool resources are supposed to be destroyed before Reset is called.
2098 * Implicit resources stay however. So this means we have an implicit render target
2099 * or depth stencil. The content may be destroyed, but we still have to tear down
2100 * opengl resources, so we cannot leave early.
2101 *
2102 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
2103 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
2104 * or the depth stencil into an FBO the texture or render buffer will be removed
2105 * and all flags get lost
2106 */
2107 if (!(surface->flags & SFLAG_PBO))
2108 surface_init_sysmem(surface);
2109 /* We also get here when the ddraw swapchain is destroyed, for example
2110 * for a mode switch. In this case this surface won't necessarily be
2111 * an implicit surface. We have to mark it lost so that the
2112 * application can restore it after the mode switch. */
2113 surface->flags |= SFLAG_LOST;
2114 }
2115 else
2116 {
2117 /* Load the surface into system memory */
2118 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2119 surface_modify_location(surface, surface->draw_binding, FALSE);
2120 }
2121 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
2122 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
2123 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
2124
2125 context = context_acquire(device, NULL);
2126 gl_info = context->gl_info;
2127
2128 /* Destroy PBOs, but load them into real sysmem before */
2129 if (surface->flags & SFLAG_PBO)
2130 surface_remove_pbo(surface, gl_info);
2131
2132 /* Destroy fbo render buffers. This is needed for implicit render targets, for
2133 * all application-created targets the application has to release the surface
2134 * before calling _Reset
2135 */
2136 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2137 {
2138 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
2139 list_remove(&entry->entry);
2140 HeapFree(GetProcessHeap(), 0, entry);
2141 }
2142 list_init(&surface->renderbuffers);
2143 surface->current_renderbuffer = NULL;
2144
2145 /* If we're in a texture, the texture name belongs to the texture.
2146 * Otherwise, destroy it. */
2147 if (!surface->container)
2148 {
2149#ifdef VBOX_WITH_WINE_FIX_TEXCLEAR
2150 if (surface->texture_name)
2151#endif
2152 {
2153#ifdef VBOX_WITH_WDDM
2154 texture_gl_delete(surface->texture_name);
2155#else
2156 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
2157#endif
2158 surface->texture_name = 0;
2159 }
2160#ifdef VBOX_WITH_WINE_FIX_TEXCLEAR
2161 if (surface->texture_name_srgb)
2162#endif
2163 {
2164#ifdef VBOX_WITH_WDDM
2165 texture_gl_delete(surface->texture_name_srgb);
2166#else
2167 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name_srgb);
2168#endif
2169 surface->texture_name_srgb = 0;
2170 }
2171 }
2172 if (surface->rb_multisample)
2173 {
2174 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
2175 surface->rb_multisample = 0;
2176 }
2177 if (surface->rb_resolved)
2178 {
2179 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
2180 surface->rb_resolved = 0;
2181 }
2182
2183 context_release(context);
2184
2185 resource_unload(resource);
2186}
2187
2188static const struct wined3d_resource_ops surface_resource_ops =
2189{
2190 surface_unload,
2191};
2192
2193static const struct wined3d_surface_ops surface_ops =
2194{
2195 surface_private_setup,
2196 surface_realize_palette,
2197 surface_map,
2198 surface_unmap,
2199};
2200
2201/*****************************************************************************
2202 * Initializes the GDI surface, aka creates the DIB section we render to
2203 * The DIB section creation is done by calling GetDC, which will create the
2204 * section and releasing the dc to allow the app to use it. The dib section
2205 * will stay until the surface is released
2206 *
2207 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
2208 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
2209 * avoid confusion in the shared surface code.
2210 *
2211 * Returns:
2212 * WINED3D_OK on success
2213 * The return values of called methods on failure
2214 *
2215 *****************************************************************************/
2216static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
2217{
2218 HRESULT hr;
2219
2220 TRACE("surface %p.\n", surface);
2221
2222 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
2223 {
2224 ERR("Overlays not yet supported by GDI surfaces.\n");
2225 return WINED3DERR_INVALIDCALL;
2226 }
2227
2228 /* Sysmem textures have memory already allocated - release it,
2229 * this avoids an unnecessary memcpy. */
2230 hr = surface_create_dib_section(surface);
2231 if (SUCCEEDED(hr))
2232 {
2233 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2234 surface->resource.heapMemory = NULL;
2235 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2236 }
2237
2238 /* We don't mind the nonpow2 stuff in GDI. */
2239 surface->pow2Width = surface->resource.width;
2240 surface->pow2Height = surface->resource.height;
2241
2242 return WINED3D_OK;
2243}
2244
2245static void gdi_surface_realize_palette(struct wined3d_surface *surface)
2246{
2247 struct wined3d_palette *palette = surface->palette;
2248
2249 TRACE("surface %p.\n", surface);
2250
2251 if (!palette) return;
2252
2253 if (surface->flags & SFLAG_DIBSECTION)
2254 {
2255 RGBQUAD col[256];
2256 unsigned int i;
2257
2258 TRACE("Updating the DC's palette.\n");
2259
2260 for (i = 0; i < 256; ++i)
2261 {
2262 col[i].rgbRed = palette->palents[i].peRed;
2263 col[i].rgbGreen = palette->palents[i].peGreen;
2264 col[i].rgbBlue = palette->palents[i].peBlue;
2265 col[i].rgbReserved = 0;
2266 }
2267 SetDIBColorTable(surface->hDC, 0, 256, col);
2268 }
2269
2270 /* Update the image because of the palette change. Some games like e.g.
2271 * Red Alert call SetEntries a lot to implement fading. */
2272 /* Tell the swapchain to update the screen. */
2273 if (surface->swapchain && surface == surface->swapchain->front_buffer)
2274 x11_copy_to_screen(surface->swapchain, NULL);
2275}
2276
2277static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
2278{
2279 TRACE("surface %p, rect %s, flags %#x.\n",
2280 surface, wine_dbgstr_rect(rect), flags);
2281
2282 if (!(surface->flags & SFLAG_DIBSECTION))
2283 {
2284 HRESULT hr;
2285
2286 /* This happens on gdi surfaces if the application set a user pointer
2287 * and resets it. Recreate the DIB section. */
2288 if (FAILED(hr = surface_create_dib_section(surface)))
2289 {
2290 ERR("Failed to create dib section, hr %#x.\n", hr);
2291 return;
2292 }
2293 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2294 surface->resource.heapMemory = NULL;
2295 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2296 }
2297}
2298
2299static void gdi_surface_unmap(struct wined3d_surface *surface)
2300{
2301 TRACE("surface %p.\n", surface);
2302
2303 /* Tell the swapchain to update the screen. */
2304 if (surface->swapchain && surface == surface->swapchain->front_buffer)
2305 x11_copy_to_screen(surface->swapchain, &surface->lockedRect);
2306
2307 memset(&surface->lockedRect, 0, sizeof(RECT));
2308}
2309
2310static const struct wined3d_surface_ops gdi_surface_ops =
2311{
2312 gdi_surface_private_setup,
2313 gdi_surface_realize_palette,
2314 gdi_surface_map,
2315 gdi_surface_unmap,
2316};
2317
2318void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb)
2319{
2320 GLuint *name;
2321 DWORD flag;
2322
2323 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
2324
2325 if(srgb)
2326 {
2327 name = &surface->texture_name_srgb;
2328 flag = SFLAG_INSRGBTEX;
2329 }
2330 else
2331 {
2332 name = &surface->texture_name;
2333 flag = SFLAG_INTEXTURE;
2334 }
2335
2336 if (!*name && new_name)
2337 {
2338 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2339 * surface has no texture name yet. See if we can get rid of this. */
2340 if (surface->flags & flag)
2341 {
2342 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
2343#ifndef VBOX_WITH_WDDM
2344 surface_modify_location(surface, flag, FALSE);
2345#endif
2346 }
2347 }
2348
2349#ifdef VBOX_WITH_WDDM
2350 if (VBOXSHRC_IS_SHARED(surface))
2351 {
2352 Assert(VBOXSHRC_GET_SHAREHANDLE(surface) == NULL
2353 || (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface) == new_name
2354 || new_name == 0 /* on cleanup */);
2355 VBOXSHRC_SET_SHAREHANDLE(surface, new_name);
2356 }
2357#endif
2358 *name = new_name;
2359 surface_force_reload(surface);
2360}
2361
2362void surface_set_texture_target(struct wined3d_surface *surface, GLenum target, GLint level)
2363{
2364 TRACE("surface %p, target %#x.\n", surface, target);
2365
2366 if (surface->texture_target != target)
2367 {
2368 if (target == GL_TEXTURE_RECTANGLE_ARB)
2369 {
2370 surface->flags &= ~SFLAG_NORMCOORD;
2371 }
2372 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2373 {
2374 surface->flags |= SFLAG_NORMCOORD;
2375 }
2376 }
2377 surface->texture_target = target;
2378 surface->texture_level = level;
2379 surface_force_reload(surface);
2380}
2381
2382/* This call just downloads data, the caller is responsible for binding the
2383 * correct texture. */
2384/* Context activation is done by the caller. */
2385static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2386{
2387 const struct wined3d_format *format = surface->resource.format;
2388
2389 /* Only support read back of converted P8 surfaces. */
2390 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2391 {
2392 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2393 return;
2394 }
2395
2396 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2397 {
2398 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2399 surface, surface->texture_level, format->glFormat, format->glType,
2400 surface->resource.allocatedMemory);
2401
2402 if (surface->flags & SFLAG_PBO)
2403 {
2404 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2405 checkGLcall("glBindBufferARB");
2406 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2407 checkGLcall("glGetCompressedTexImageARB");
2408 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2409 checkGLcall("glBindBufferARB");
2410 }
2411 else
2412 {
2413 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2414 surface->texture_level, surface->resource.allocatedMemory));
2415 checkGLcall("glGetCompressedTexImageARB");
2416 }
2417
2418 }
2419 else
2420 {
2421 void *mem;
2422 GLenum gl_format = format->glFormat;
2423 GLenum gl_type = format->glType;
2424 int src_pitch = 0;
2425 int dst_pitch = 0;
2426
2427 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2428 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2429 {
2430 gl_format = GL_ALPHA;
2431 gl_type = GL_UNSIGNED_BYTE;
2432 }
2433
2434 if (surface->flags & SFLAG_NONPOW2)
2435 {
2436 unsigned char alignment = surface->resource.device->surface_alignment;
2437 src_pitch = format->byte_count * surface->pow2Width;
2438 dst_pitch = wined3d_surface_get_pitch(surface);
2439 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2440 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2441 }
2442 else
2443 {
2444 mem = surface->resource.allocatedMemory;
2445 }
2446
2447 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2448 surface, surface->texture_level, gl_format, gl_type, mem);
2449
2450 if (surface->flags & SFLAG_PBO)
2451 {
2452 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2453 checkGLcall("glBindBufferARB");
2454
2455 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2456 gl_format, gl_type, NULL);
2457 checkGLcall("glGetTexImage");
2458
2459 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2460 checkGLcall("glBindBufferARB");
2461 }
2462 else
2463 {
2464 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2465 gl_format, gl_type, mem);
2466 checkGLcall("glGetTexImage");
2467 }
2468
2469 if (surface->flags & SFLAG_NONPOW2)
2470 {
2471 const BYTE *src_data;
2472 BYTE *dst_data;
2473 UINT y;
2474 /*
2475 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2476 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2477 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2478 *
2479 * We're doing this...
2480 *
2481 * instead of boxing the texture :
2482 * |<-texture width ->| -->pow2width| /\
2483 * |111111111111111111| | |
2484 * |222 Texture 222222| boxed empty | texture height
2485 * |3333 Data 33333333| | |
2486 * |444444444444444444| | \/
2487 * ----------------------------------- |
2488 * | boxed empty | boxed empty | pow2height
2489 * | | | \/
2490 * -----------------------------------
2491 *
2492 *
2493 * we're repacking the data to the expected texture width
2494 *
2495 * |<-texture width ->| -->pow2width| /\
2496 * |111111111111111111222222222222222| |
2497 * |222333333333333333333444444444444| texture height
2498 * |444444 | |
2499 * | | \/
2500 * | | |
2501 * | empty | pow2height
2502 * | | \/
2503 * -----------------------------------
2504 *
2505 * == is the same as
2506 *
2507 * |<-texture width ->| /\
2508 * |111111111111111111|
2509 * |222222222222222222|texture height
2510 * |333333333333333333|
2511 * |444444444444444444| \/
2512 * --------------------
2513 *
2514 * this also means that any references to allocatedMemory should work with the data as if were a
2515 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2516 *
2517 * internally the texture is still stored in a boxed format so any references to textureName will
2518 * get a boxed texture with width pow2width and not a texture of width resource.width.
2519 *
2520 * Performance should not be an issue, because applications normally do not lock the surfaces when
2521 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2522 * and doesn't have to be re-read. */
2523 src_data = mem;
2524 dst_data = surface->resource.allocatedMemory;
2525 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2526 for (y = 0; y < surface->resource.height; ++y)
2527 {
2528 memcpy(dst_data, src_data, dst_pitch);
2529 src_data += src_pitch;
2530 dst_data += dst_pitch;
2531 }
2532
2533 HeapFree(GetProcessHeap(), 0, mem);
2534 }
2535 }
2536
2537 /* Surface has now been downloaded */
2538 surface->flags |= SFLAG_INSYSMEM;
2539}
2540
2541/* This call just uploads data, the caller is responsible for binding the
2542 * correct texture. */
2543/* Context activation is done by the caller. */
2544static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2545 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2546 BOOL srgb, const struct wined3d_bo_address *data)
2547{
2548 UINT update_w = src_rect->right - src_rect->left;
2549 UINT update_h = src_rect->bottom - src_rect->top;
2550
2551 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2552 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2553 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2554
2555 if (surface->resource.map_count)
2556 {
2557 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2558 surface->flags |= SFLAG_PIN_SYSMEM;
2559 }
2560
2561 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2562 {
2563 update_h *= format->height_scale.numerator;
2564 update_h /= format->height_scale.denominator;
2565 }
2566
2567 if (data->buffer_object)
2568 {
2569 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2570 checkGLcall("glBindBufferARB");
2571 }
2572
2573 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2574 {
2575 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2576 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2577 const BYTE *addr = data->addr;
2578 GLenum internal;
2579
2580 addr += (src_rect->top / format->block_height) * src_pitch;
2581 addr += (src_rect->left / format->block_width) * format->block_byte_count;
2582
2583 if (srgb)
2584 internal = format->glGammaInternal;
2585 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2586 internal = format->rtInternal;
2587 else
2588 internal = format->glInternal;
2589
2590 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2591 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2592 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2593
2594 if (row_length == src_pitch)
2595 {
2596 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2597 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2598 }
2599 else
2600 {
2601 UINT row, y;
2602
2603 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2604 * can't use the unpack row length like below. */
2605 for (row = 0, y = dst_point->y; row < row_count; ++row)
2606 {
2607 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2608 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2609 y += format->block_height;
2610 addr += src_pitch;
2611 }
2612 }
2613 checkGLcall("glCompressedTexSubImage2DARB");
2614 }
2615 else
2616 {
2617 const BYTE *addr = data->addr;
2618
2619 addr += src_rect->top * src_pitch;
2620 addr += src_rect->left * format->byte_count;
2621
2622 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2623 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2624 update_w, update_h, format->glFormat, format->glType, addr);
2625
2626 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2627 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2628 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2629 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2630 checkGLcall("glTexSubImage2D");
2631 }
2632
2633 if (data->buffer_object)
2634 {
2635 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2636 checkGLcall("glBindBufferARB");
2637 }
2638
2639 if (wined3d_settings.strict_draw_ordering)
2640 gl_info->gl_ops.gl.p_glFlush();
2641
2642 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2643 {
2644 struct wined3d_device *device = surface->resource.device;
2645 unsigned int i;
2646
2647 for (i = 0; i < device->context_count; ++i)
2648 {
2649 context_surface_update(device->contexts[i], surface);
2650 }
2651 }
2652}
2653
2654static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2655 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2656{
2657 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2658 const struct wined3d_device *device = surface->resource.device;
2659 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2660 BOOL blit_supported = FALSE;
2661
2662 /* Copy the default values from the surface. Below we might perform fixups */
2663 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2664 *format = *surface->resource.format;
2665 *conversion_type = WINED3D_CT_NONE;
2666
2667 /* Ok, now look if we have to do any conversion */
2668 switch (surface->resource.format->id)
2669 {
2670 case WINED3DFMT_P8_UINT:
2671 /* Below the call to blit_supported is disabled for Wine 1.2
2672 * because the function isn't operating correctly yet. At the
2673 * moment 8-bit blits are handled in software and if certain GL
2674 * extensions are around, surface conversion is performed at
2675 * upload time. The blit_supported call recognizes it as a
2676 * destination fixup. This type of upload 'fixup' and 8-bit to
2677 * 8-bit blits need to be handled by the blit_shader.
2678 * TODO: get rid of this #if 0. */
2679#if 0
2680 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2681 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2682 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2683#endif
2684 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2685
2686 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2687 * texturing. Further also use conversion in case of color keying.
2688 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2689 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2690 * conflicts with this.
2691 */
2692 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2693 || colorkey_active || !use_texturing)
2694 {
2695 format->glFormat = GL_RGBA;
2696 format->glInternal = GL_RGBA;
2697 format->glType = GL_UNSIGNED_BYTE;
2698 format->conv_byte_count = 4;
2699 if (colorkey_active)
2700 *conversion_type = WINED3D_CT_PALETTED_CK;
2701 else
2702 *conversion_type = WINED3D_CT_PALETTED;
2703 }
2704 break;
2705
2706 case WINED3DFMT_B2G3R3_UNORM:
2707 /* **********************
2708 GL_UNSIGNED_BYTE_3_3_2
2709 ********************** */
2710 if (colorkey_active) {
2711 /* This texture format will never be used.. So do not care about color keying
2712 up until the point in time it will be needed :-) */
2713 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2714 }
2715 break;
2716
2717 case WINED3DFMT_B5G6R5_UNORM:
2718 if (colorkey_active)
2719 {
2720 *conversion_type = WINED3D_CT_CK_565;
2721 format->glFormat = GL_RGBA;
2722 format->glInternal = GL_RGB5_A1;
2723 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2724 format->conv_byte_count = 2;
2725 }
2726 break;
2727
2728 case WINED3DFMT_B5G5R5X1_UNORM:
2729 if (colorkey_active)
2730 {
2731 *conversion_type = WINED3D_CT_CK_5551;
2732 format->glFormat = GL_BGRA;
2733 format->glInternal = GL_RGB5_A1;
2734 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2735 format->conv_byte_count = 2;
2736 }
2737 break;
2738
2739 case WINED3DFMT_B8G8R8_UNORM:
2740 if (colorkey_active)
2741 {
2742 *conversion_type = WINED3D_CT_CK_RGB24;
2743 format->glFormat = GL_RGBA;
2744 format->glInternal = GL_RGBA8;
2745 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2746 format->conv_byte_count = 4;
2747 }
2748 break;
2749
2750 case WINED3DFMT_B8G8R8X8_UNORM:
2751 if (colorkey_active)
2752 {
2753 *conversion_type = WINED3D_CT_RGB32_888;
2754 format->glFormat = GL_RGBA;
2755 format->glInternal = GL_RGBA8;
2756 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2757 format->conv_byte_count = 4;
2758 }
2759 break;
2760
2761 case WINED3DFMT_B8G8R8A8_UNORM:
2762 if (colorkey_active)
2763 {
2764 *conversion_type = WINED3D_CT_CK_ARGB32;
2765 format->conv_byte_count = 4;
2766 }
2767 break;
2768
2769 default:
2770 break;
2771 }
2772
2773 if (*conversion_type != WINED3D_CT_NONE)
2774 {
2775 format->rtInternal = format->glInternal;
2776 format->glGammaInternal = format->glInternal;
2777 }
2778
2779 return WINED3D_OK;
2780}
2781
2782static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2783{
2784 UINT width_mask, height_mask;
2785
2786 if (!rect->left && !rect->top
2787 && rect->right == surface->resource.width
2788 && rect->bottom == surface->resource.height)
2789 return TRUE;
2790
2791 /* This assumes power of two block sizes, but NPOT block sizes would be
2792 * silly anyway. */
2793 width_mask = surface->resource.format->block_width - 1;
2794 height_mask = surface->resource.format->block_height - 1;
2795
2796 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2797 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2798 return TRUE;
2799
2800 return FALSE;
2801}
2802
2803HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2804 struct wined3d_surface *src_surface, const RECT *src_rect)
2805{
2806 const struct wined3d_format *src_format;
2807 const struct wined3d_format *dst_format;
2808 const struct wined3d_gl_info *gl_info;
2809 enum wined3d_conversion_type convert;
2810 struct wined3d_context *context;
2811 struct wined3d_bo_address data;
2812 struct wined3d_format format;
2813 UINT update_w, update_h;
2814 UINT dst_w, dst_h;
2815 RECT r, dst_rect;
2816 UINT src_pitch;
2817 POINT p;
2818
2819 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2820 dst_surface, wine_dbgstr_point(dst_point),
2821 src_surface, wine_dbgstr_rect(src_rect));
2822
2823 src_format = src_surface->resource.format;
2824 dst_format = dst_surface->resource.format;
2825
2826 if (src_format->id != dst_format->id)
2827 {
2828 WARN("Source and destination surfaces should have the same format.\n");
2829 return WINED3DERR_INVALIDCALL;
2830 }
2831
2832 if (!dst_point)
2833 {
2834 p.x = 0;
2835 p.y = 0;
2836 dst_point = &p;
2837 }
2838 else if (dst_point->x < 0 || dst_point->y < 0)
2839 {
2840 WARN("Invalid destination point.\n");
2841 return WINED3DERR_INVALIDCALL;
2842 }
2843
2844 if (!src_rect)
2845 {
2846 r.left = 0;
2847 r.top = 0;
2848 r.right = src_surface->resource.width;
2849 r.bottom = src_surface->resource.height;
2850 src_rect = &r;
2851 }
2852 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2853 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2854 {
2855 WARN("Invalid source rectangle.\n");
2856 return WINED3DERR_INVALIDCALL;
2857 }
2858
2859 dst_w = dst_surface->resource.width;
2860 dst_h = dst_surface->resource.height;
2861
2862 update_w = src_rect->right - src_rect->left;
2863 update_h = src_rect->bottom - src_rect->top;
2864
2865 if (update_w > dst_w || dst_point->x > dst_w - update_w
2866 || update_h > dst_h || dst_point->y > dst_h - update_h)
2867 {
2868 WARN("Destination out of bounds.\n");
2869 return WINED3DERR_INVALIDCALL;
2870 }
2871
2872 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2873 {
2874 WARN("Source rectangle not block-aligned.\n");
2875 return WINED3DERR_INVALIDCALL;
2876 }
2877
2878 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2879 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2880 {
2881 WARN("Destination rectangle not block-aligned.\n");
2882 return WINED3DERR_INVALIDCALL;
2883 }
2884
2885 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2886 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2887 if (convert != WINED3D_CT_NONE || format.convert)
2888 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2889
2890 context = context_acquire(dst_surface->resource.device, NULL);
2891 gl_info = context->gl_info;
2892
2893 /* Only load the surface for partial updates. For newly allocated texture
2894 * the texture wouldn't be the current location, and we'd upload zeroes
2895 * just to overwrite them again. */
2896 if (update_w == dst_w && update_h == dst_h)
2897 surface_prepare_texture(dst_surface, context, FALSE);
2898 else
2899 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2900 surface_bind(dst_surface, context, FALSE);
2901
2902 data.buffer_object = src_surface->pbo;
2903 data.addr = src_surface->resource.allocatedMemory;
2904 src_pitch = wined3d_surface_get_pitch(src_surface);
2905
2906 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2907
2908 invalidate_active_texture(dst_surface->resource.device, context);
2909
2910 context_release(context);
2911
2912 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2913 return WINED3D_OK;
2914}
2915
2916/* This call just allocates the texture, the caller is responsible for binding
2917 * the correct texture. */
2918/* Context activation is done by the caller. */
2919static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2920 const struct wined3d_format *format, BOOL srgb)
2921{
2922 BOOL enable_client_storage = FALSE;
2923 GLsizei width = surface->pow2Width;
2924 GLsizei height = surface->pow2Height;
2925 const BYTE *mem = NULL;
2926 GLenum internal;
2927
2928#ifdef VBOX_WITH_WDDM
2929 if (VBOXSHRC_IS_SHARED_OPENED(surface))
2930 {
2931 ERR("trying to allocate shared openned resource!!, ignoring..\n");
2932 return;
2933 }
2934#endif
2935
2936 if (srgb)
2937 {
2938 internal = format->glGammaInternal;
2939 }
2940 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2941 {
2942 internal = format->rtInternal;
2943 }
2944 else
2945 {
2946 internal = format->glInternal;
2947 }
2948
2949 if (!internal)
2950 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2951
2952 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2953 {
2954 height *= format->height_scale.numerator;
2955 height /= format->height_scale.denominator;
2956 }
2957
2958 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",
2959 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2960 internal, width, height, format->glFormat, format->glType);
2961
2962 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2963 {
2964 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2965 || !surface->resource.allocatedMemory)
2966 {
2967 /* In some cases we want to disable client storage.
2968 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2969 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2970 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2971 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2972 */
2973 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2974 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2975 surface->flags &= ~SFLAG_CLIENT;
2976 enable_client_storage = TRUE;
2977 }
2978 else
2979 {
2980 surface->flags |= SFLAG_CLIENT;
2981
2982 /* Point OpenGL to our allocated texture memory. Do not use
2983 * resource.allocatedMemory here because it might point into a
2984 * PBO. Instead use heapMemory, but get the alignment right. */
2985 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2986 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2987 }
2988 }
2989
2990 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2991 {
2992 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
2993 internal, width, height, 0, surface->resource.size, mem));
2994 checkGLcall("glCompressedTexImage2DARB");
2995 }
2996 else
2997 {
2998 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
2999 internal, width, height, 0, format->glFormat, format->glType, mem);
3000 checkGLcall("glTexImage2D");
3001 }
3002
3003 if (enable_client_storage)
3004 {
3005 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
3006 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
3007 }
3008}
3009
3010/* In D3D the depth stencil dimensions have to be greater than or equal to the
3011 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
3012/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
3013/* Context activation is done by the caller. */
3014void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
3015{
3016 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
3017 struct wined3d_renderbuffer_entry *entry;
3018 GLuint renderbuffer = 0;
3019 unsigned int src_width, src_height;
3020 unsigned int width, height;
3021
3022 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
3023 {
3024 width = rt->pow2Width;
3025 height = rt->pow2Height;
3026 }
3027 else
3028 {
3029 width = surface->pow2Width;
3030 height = surface->pow2Height;
3031 }
3032
3033 src_width = surface->pow2Width;
3034 src_height = surface->pow2Height;
3035
3036 /* A depth stencil smaller than the render target is not valid */
3037 if (width > src_width || height > src_height) return;
3038
3039 /* Remove any renderbuffer set if the sizes match */
3040 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
3041 || (width == src_width && height == src_height))
3042 {
3043 surface->current_renderbuffer = NULL;
3044 return;
3045 }
3046
3047 /* Look if we've already got a renderbuffer of the correct dimensions */
3048 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
3049 {
3050 if (entry->width == width && entry->height == height)
3051 {
3052 renderbuffer = entry->id;
3053 surface->current_renderbuffer = entry;
3054 break;
3055 }
3056 }
3057
3058 if (!renderbuffer)
3059 {
3060 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
3061 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
3062 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
3063 surface->resource.format->glInternal, width, height);
3064
3065 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
3066 entry->width = width;
3067 entry->height = height;
3068 entry->id = renderbuffer;
3069 list_add_head(&surface->renderbuffers, &entry->entry);
3070
3071 surface->current_renderbuffer = entry;
3072 }
3073
3074 checkGLcall("set_compatible_renderbuffer");
3075}
3076
3077GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
3078{
3079 const struct wined3d_swapchain *swapchain = surface->swapchain;
3080
3081 TRACE("surface %p.\n", surface);
3082
3083 if (!swapchain)
3084 {
3085 ERR("Surface %p is not on a swapchain.\n", surface);
3086 return GL_NONE;
3087 }
3088
3089 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
3090 {
3091 if (swapchain->render_to_fbo)
3092 {
3093 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
3094 return GL_COLOR_ATTACHMENT0;
3095 }
3096 TRACE("Returning GL_BACK\n");
3097 return GL_BACK;
3098 }
3099 else if (surface == swapchain->front_buffer)
3100 {
3101 TRACE("Returning GL_FRONT\n");
3102 return GL_FRONT;
3103 }
3104
3105 FIXME("Higher back buffer, returning GL_BACK\n");
3106 return GL_BACK;
3107}
3108
3109/* Slightly inefficient way to handle multiple dirty rects but it works :) */
3110void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
3111{
3112 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
3113
3114 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
3115 /* No partial locking for textures yet. */
3116 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3117
3118 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3119 if (dirty_rect)
3120 {
3121 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
3122 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
3123 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
3124 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
3125 }
3126 else
3127 {
3128 surface->dirtyRect.left = 0;
3129 surface->dirtyRect.top = 0;
3130 surface->dirtyRect.right = surface->resource.width;
3131 surface->dirtyRect.bottom = surface->resource.height;
3132 }
3133
3134 /* if the container is a texture then mark it dirty. */
3135 if (surface->container)
3136 {
3137 TRACE("Passing to container.\n");
3138 wined3d_texture_set_dirty(surface->container, TRUE);
3139 }
3140}
3141
3142HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
3143{
3144 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
3145 BOOL ck_changed;
3146
3147 TRACE("surface %p, srgb %#x.\n", surface, srgb);
3148
3149 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
3150 {
3151 ERR("Not supported on scratch surfaces.\n");
3152 return WINED3DERR_INVALIDCALL;
3153 }
3154
3155 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
3156
3157 /* Reload if either the texture and sysmem have different ideas about the
3158 * color key, or the actual key values changed. */
3159 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
3160 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
3161 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
3162 {
3163 TRACE("Reloading because of color keying\n");
3164 /* To perform the color key conversion we need a sysmem copy of
3165 * the surface. Make sure we have it. */
3166
3167 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3168 /* Make sure the texture is reloaded because of the color key change,
3169 * this kills performance though :( */
3170 /* TODO: This is not necessarily needed with hw palettized texture support. */
3171 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3172 /* Switching color keying on / off may change the internal format. */
3173 if (ck_changed)
3174 surface_force_reload(surface);
3175 }
3176 else if (!(surface->flags & flag))
3177 {
3178 TRACE("Reloading because surface is dirty.\n");
3179 }
3180 else
3181 {
3182 TRACE("surface is already in texture\n");
3183 return WINED3D_OK;
3184 }
3185
3186 /* No partial locking for textures yet. */
3187 surface_load_location(surface, flag, NULL);
3188 surface_evict_sysmem(surface);
3189
3190 return WINED3D_OK;
3191}
3192
3193/* See also float_16_to_32() in wined3d_private.h */
3194static inline unsigned short float_32_to_16(const float *in)
3195{
3196 int exp = 0;
3197 float tmp = fabsf(*in);
3198 unsigned int mantissa;
3199 unsigned short ret;
3200
3201 /* Deal with special numbers */
3202 if (*in == 0.0f)
3203 return 0x0000;
3204 if (isnan(*in))
3205 return 0x7c01;
3206 if (isinf(*in))
3207 return (*in < 0.0f ? 0xfc00 : 0x7c00);
3208
3209 if (tmp < powf(2, 10))
3210 {
3211 do
3212 {
3213 tmp = tmp * 2.0f;
3214 exp--;
3215 } while (tmp < powf(2, 10));
3216 }
3217 else if (tmp >= powf(2, 11))
3218 {
3219 do
3220 {
3221 tmp /= 2.0f;
3222 exp++;
3223 } while (tmp >= powf(2, 11));
3224 }
3225
3226 mantissa = (unsigned int)tmp;
3227 if (tmp - mantissa >= 0.5f)
3228 ++mantissa; /* Round to nearest, away from zero. */
3229
3230 exp += 10; /* Normalize the mantissa. */
3231 exp += 15; /* Exponent is encoded with excess 15. */
3232
3233 if (exp > 30) /* too big */
3234 {
3235 ret = 0x7c00; /* INF */
3236 }
3237 else if (exp <= 0)
3238 {
3239 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
3240 while (exp <= 0)
3241 {
3242 mantissa = mantissa >> 1;
3243 ++exp;
3244 }
3245 ret = mantissa & 0x3ff;
3246 }
3247 else
3248 {
3249 ret = (exp << 10) | (mantissa & 0x3ff);
3250 }
3251
3252 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
3253 return ret;
3254}
3255
3256ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3257{
3258 ULONG refcount;
3259
3260 TRACE("surface %p, swapchain %p, container %p.\n",
3261 surface, surface->swapchain, surface->container);
3262
3263 if (surface->swapchain)
3264 return wined3d_swapchain_incref(surface->swapchain);
3265
3266 if (surface->container)
3267 return wined3d_texture_incref(surface->container);
3268
3269 refcount = InterlockedIncrement(&surface->resource.ref);
3270 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3271
3272 return refcount;
3273}
3274
3275/* Do not call while under the GL lock. */
3276ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3277{
3278 ULONG refcount;
3279
3280 TRACE("surface %p, swapchain %p, container %p.\n",
3281 surface, surface->swapchain, surface->container);
3282
3283 if (surface->swapchain)
3284 return wined3d_swapchain_decref(surface->swapchain);
3285
3286 if (surface->container)
3287 return wined3d_texture_decref(surface->container);
3288
3289 refcount = InterlockedDecrement(&surface->resource.ref);
3290 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3291
3292 if (!refcount)
3293 {
3294 surface_cleanup(surface);
3295 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3296
3297 TRACE("Destroyed surface %p.\n", surface);
3298 HeapFree(GetProcessHeap(), 0, surface);
3299 }
3300
3301 return refcount;
3302}
3303
3304DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3305{
3306 return resource_set_priority(&surface->resource, priority);
3307}
3308
3309DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3310{
3311 return resource_get_priority(&surface->resource);
3312}
3313
3314void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3315{
3316 TRACE("surface %p.\n", surface);
3317
3318 if (!surface->resource.device->d3d_initialized)
3319 {
3320 ERR("D3D not initialized.\n");
3321 return;
3322 }
3323
3324 surface_internal_preload(surface, SRGB_ANY);
3325}
3326
3327void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3328{
3329 TRACE("surface %p.\n", surface);
3330
3331 return surface->resource.parent;
3332}
3333
3334struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3335{
3336 TRACE("surface %p.\n", surface);
3337
3338 return &surface->resource;
3339}
3340
3341HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3342{
3343 TRACE("surface %p, flags %#x.\n", surface, flags);
3344
3345 switch (flags)
3346 {
3347 case WINEDDGBS_CANBLT:
3348 case WINEDDGBS_ISBLTDONE:
3349 return WINED3D_OK;
3350
3351 default:
3352 return WINED3DERR_INVALIDCALL;
3353 }
3354}
3355
3356HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3357{
3358 TRACE("surface %p, flags %#x.\n", surface, flags);
3359
3360 /* XXX: DDERR_INVALIDSURFACETYPE */
3361
3362 switch (flags)
3363 {
3364 case WINEDDGFS_CANFLIP:
3365 case WINEDDGFS_ISFLIPDONE:
3366 return WINED3D_OK;
3367
3368 default:
3369 return WINED3DERR_INVALIDCALL;
3370 }
3371}
3372
3373HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3374{
3375 TRACE("surface %p.\n", surface);
3376
3377 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3378 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3379}
3380
3381HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3382{
3383 TRACE("surface %p.\n", surface);
3384
3385 surface->flags &= ~SFLAG_LOST;
3386 return WINED3D_OK;
3387}
3388
3389void CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3390{
3391 TRACE("surface %p, palette %p.\n", surface, palette);
3392
3393 if (surface->palette == palette)
3394 {
3395 TRACE("Nop palette change.\n");
3396 return;
3397 }
3398
3399 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3400 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3401
3402 surface->palette = palette;
3403
3404 if (palette)
3405 {
3406 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3407 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3408
3409 surface->surface_ops->surface_realize_palette(surface);
3410 }
3411}
3412
3413HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3414 DWORD flags, const struct wined3d_color_key *color_key)
3415{
3416 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3417
3418 if (flags & WINEDDCKEY_COLORSPACE)
3419 {
3420 FIXME(" colorkey value not supported (%08x) !\n", flags);
3421 return WINED3DERR_INVALIDCALL;
3422 }
3423
3424 /* Dirtify the surface, but only if a key was changed. */
3425 if (color_key)
3426 {
3427 switch (flags & ~WINEDDCKEY_COLORSPACE)
3428 {
3429 case WINEDDCKEY_DESTBLT:
3430 surface->dst_blt_color_key = *color_key;
3431 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3432 break;
3433
3434 case WINEDDCKEY_DESTOVERLAY:
3435 surface->dst_overlay_color_key = *color_key;
3436 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3437 break;
3438
3439 case WINEDDCKEY_SRCOVERLAY:
3440 surface->src_overlay_color_key = *color_key;
3441 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3442 break;
3443
3444 case WINEDDCKEY_SRCBLT:
3445 surface->src_blt_color_key = *color_key;
3446 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3447 break;
3448 }
3449 }
3450 else
3451 {
3452 switch (flags & ~WINEDDCKEY_COLORSPACE)
3453 {
3454 case WINEDDCKEY_DESTBLT:
3455 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3456 break;
3457
3458 case WINEDDCKEY_DESTOVERLAY:
3459 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3460 break;
3461
3462 case WINEDDCKEY_SRCOVERLAY:
3463 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3464 break;
3465
3466 case WINEDDCKEY_SRCBLT:
3467 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3468 break;
3469 }
3470 }
3471
3472 return WINED3D_OK;
3473}
3474
3475struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3476{
3477 TRACE("surface %p.\n", surface);
3478
3479 return surface->palette;
3480}
3481
3482DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3483{
3484 const struct wined3d_format *format = surface->resource.format;
3485 DWORD pitch;
3486
3487 TRACE("surface %p.\n", surface);
3488
3489 if (surface->pitch)
3490 return surface->pitch;
3491
3492 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3493 {
3494 /* Since compressed formats are block based, pitch means the amount of
3495 * bytes to the next row of block rather than the next row of pixels. */
3496 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3497 pitch = row_block_count * format->block_byte_count;
3498 }
3499 else
3500 {
3501 unsigned char alignment = surface->resource.device->surface_alignment;
3502 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3503 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3504 }
3505
3506 TRACE("Returning %u.\n", pitch);
3507
3508 return pitch;
3509}
3510
3511HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem, UINT pitch)
3512{
3513#ifndef VBOX_WITH_WDDM
3514 TRACE("surface %p, mem %p.\n", surface, mem);
3515
3516 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3517 {
3518 WARN("Surface is mapped or the DC is in use.\n");
3519 return WINED3DERR_INVALIDCALL;
3520 }
3521
3522 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3523 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3524 {
3525 ERR("Not supported on render targets.\n");
3526 return WINED3DERR_INVALIDCALL;
3527 }
3528
3529 if (mem && mem != surface->resource.allocatedMemory)
3530 {
3531 void *release = NULL;
3532
3533 /* Do I have to copy the old surface content? */
3534 if (surface->flags & SFLAG_DIBSECTION)
3535 {
3536 DeleteDC(surface->hDC);
3537 DeleteObject(surface->dib.DIBsection);
3538 surface->dib.bitmap_data = NULL;
3539 surface->resource.allocatedMemory = NULL;
3540 surface->hDC = NULL;
3541 surface->flags &= ~SFLAG_DIBSECTION;
3542 }
3543 else if (!(surface->flags & SFLAG_USERPTR))
3544 {
3545 release = surface->resource.heapMemory;
3546 surface->resource.heapMemory = NULL;
3547 }
3548 surface->resource.allocatedMemory = mem;
3549 surface->flags |= SFLAG_USERPTR;
3550
3551 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3552 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3553
3554 /* For client textures OpenGL has to be notified. */
3555 if (surface->flags & SFLAG_CLIENT)
3556 surface_release_client_storage(surface);
3557
3558 /* Now free the old memory if any. */
3559 HeapFree(GetProcessHeap(), 0, release);
3560 }
3561 else if (surface->flags & SFLAG_USERPTR)
3562 {
3563 /* HeapMemory should be NULL already. */
3564 if (surface->resource.heapMemory)
3565 ERR("User pointer surface has heap memory allocated.\n");
3566
3567 if (!mem)
3568 {
3569 surface->resource.allocatedMemory = NULL;
3570 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3571
3572 if (surface->flags & SFLAG_CLIENT)
3573 surface_release_client_storage(surface);
3574
3575 surface_prepare_system_memory(surface);
3576 }
3577
3578 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3579 }
3580
3581 surface->pitch = pitch;
3582
3583 return WINED3D_OK;
3584#else
3585 ERR("unsupported!");
3586 return E_FAIL;
3587#endif
3588}
3589
3590HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3591{
3592 LONG w, h;
3593
3594 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3595
3596 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3597 {
3598 WARN("Not an overlay surface.\n");
3599 return WINEDDERR_NOTAOVERLAYSURFACE;
3600 }
3601
3602 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3603 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3604 surface->overlay_destrect.left = x;
3605 surface->overlay_destrect.top = y;
3606 surface->overlay_destrect.right = x + w;
3607 surface->overlay_destrect.bottom = y + h;
3608
3609 surface_draw_overlay(surface);
3610
3611 return WINED3D_OK;
3612}
3613
3614HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3615{
3616 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3617
3618 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3619 {
3620 TRACE("Not an overlay surface.\n");
3621 return WINEDDERR_NOTAOVERLAYSURFACE;
3622 }
3623
3624 if (!surface->overlay_dest)
3625 {
3626 TRACE("Overlay not visible.\n");
3627 *x = 0;
3628 *y = 0;
3629 return WINEDDERR_OVERLAYNOTVISIBLE;
3630 }
3631
3632 *x = surface->overlay_destrect.left;
3633 *y = surface->overlay_destrect.top;
3634
3635 TRACE("Returning position %d, %d.\n", *x, *y);
3636
3637 return WINED3D_OK;
3638}
3639
3640HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3641 DWORD flags, struct wined3d_surface *ref)
3642{
3643 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3644
3645 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3646 {
3647 TRACE("Not an overlay surface.\n");
3648 return WINEDDERR_NOTAOVERLAYSURFACE;
3649 }
3650
3651 return WINED3D_OK;
3652}
3653
3654HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3655 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3656{
3657 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3658 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3659
3660 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3661 {
3662 WARN("Not an overlay surface.\n");
3663 return WINEDDERR_NOTAOVERLAYSURFACE;
3664 }
3665 else if (!dst_surface)
3666 {
3667 WARN("Dest surface is NULL.\n");
3668 return WINED3DERR_INVALIDCALL;
3669 }
3670
3671 if (src_rect)
3672 {
3673 surface->overlay_srcrect = *src_rect;
3674 }
3675 else
3676 {
3677 surface->overlay_srcrect.left = 0;
3678 surface->overlay_srcrect.top = 0;
3679 surface->overlay_srcrect.right = surface->resource.width;
3680 surface->overlay_srcrect.bottom = surface->resource.height;
3681 }
3682
3683 if (dst_rect)
3684 {
3685 surface->overlay_destrect = *dst_rect;
3686 }
3687 else
3688 {
3689 surface->overlay_destrect.left = 0;
3690 surface->overlay_destrect.top = 0;
3691 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3692 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3693 }
3694
3695 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3696 {
3697 surface->overlay_dest = NULL;
3698 list_remove(&surface->overlay_entry);
3699 }
3700
3701 if (flags & WINEDDOVER_SHOW)
3702 {
3703 if (surface->overlay_dest != dst_surface)
3704 {
3705 surface->overlay_dest = dst_surface;
3706 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3707 }
3708 }
3709 else if (flags & WINEDDOVER_HIDE)
3710 {
3711 /* tests show that the rectangles are erased on hide */
3712 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3713 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3714 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3715 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3716 surface->overlay_dest = NULL;
3717 }
3718
3719 surface_draw_overlay(surface);
3720
3721 return WINED3D_OK;
3722}
3723
3724HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3725 UINT width, UINT height, enum wined3d_format_id format_id,
3726 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3727{
3728 struct wined3d_device *device = surface->resource.device;
3729 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3730 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3731 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3732
3733 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3734 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3735
3736 if (!resource_size)
3737 return WINED3DERR_INVALIDCALL;
3738
3739 if (device->d3d_initialized)
3740 surface->resource.resource_ops->resource_unload(&surface->resource);
3741
3742 if (surface->flags & SFLAG_DIBSECTION)
3743 {
3744 DeleteDC(surface->hDC);
3745 DeleteObject(surface->dib.DIBsection);
3746 surface->dib.bitmap_data = NULL;
3747 surface->flags &= ~SFLAG_DIBSECTION;
3748 }
3749
3750 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3751 surface->resource.allocatedMemory = NULL;
3752 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3753 surface->resource.heapMemory = NULL;
3754
3755 surface->resource.width = width;
3756 surface->resource.height = height;
3757 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3758 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3759 {
3760 surface->pow2Width = width;
3761 surface->pow2Height = height;
3762 }
3763 else
3764 {
3765 surface->pow2Width = surface->pow2Height = 1;
3766 while (surface->pow2Width < width)
3767 surface->pow2Width <<= 1;
3768 while (surface->pow2Height < height)
3769 surface->pow2Height <<= 1;
3770 }
3771
3772 if (surface->pow2Width != width || surface->pow2Height != height)
3773 surface->flags |= SFLAG_NONPOW2;
3774 else
3775 surface->flags &= ~SFLAG_NONPOW2;
3776
3777 surface->resource.format = format;
3778 surface->resource.multisample_type = multisample_type;
3779 surface->resource.multisample_quality = multisample_quality;
3780 surface->resource.size = resource_size;
3781
3782 if (!surface_init_sysmem(surface))
3783 return E_OUTOFMEMORY;
3784
3785 return WINED3D_OK;
3786}
3787
3788static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3789 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3790{
3791 unsigned short *dst_s;
3792 const float *src_f;
3793 unsigned int x, y;
3794
3795 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3796
3797 for (y = 0; y < h; ++y)
3798 {
3799 src_f = (const float *)(src + y * pitch_in);
3800 dst_s = (unsigned short *) (dst + y * pitch_out);
3801 for (x = 0; x < w; ++x)
3802 {
3803 dst_s[x] = float_32_to_16(src_f + x);
3804 }
3805 }
3806}
3807
3808static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3809 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3810{
3811 static const unsigned char convert_5to8[] =
3812 {
3813 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3814 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3815 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3816 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3817 };
3818 static const unsigned char convert_6to8[] =
3819 {
3820 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3821 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3822 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3823 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3824 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3825 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3826 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3827 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3828 };
3829 unsigned int x, y;
3830
3831 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3832
3833 for (y = 0; y < h; ++y)
3834 {
3835 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3836 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3837 for (x = 0; x < w; ++x)
3838 {
3839 WORD pixel = src_line[x];
3840 dst_line[x] = 0xff000000
3841 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3842 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3843 | convert_5to8[(pixel & 0x001f)];
3844 }
3845 }
3846}
3847
3848/* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3849 * in both cases we're just setting the X / Alpha channel to 0xff. */
3850static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3851 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3852{
3853 unsigned int x, y;
3854
3855 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3856
3857 for (y = 0; y < h; ++y)
3858 {
3859 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3860 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3861
3862 for (x = 0; x < w; ++x)
3863 {
3864 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3865 }
3866 }
3867}
3868
3869static inline BYTE cliptobyte(int x)
3870{
3871 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3872}
3873
3874static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3875 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3876{
3877 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3878 unsigned int x, y;
3879
3880 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3881
3882 for (y = 0; y < h; ++y)
3883 {
3884 const BYTE *src_line = src + y * pitch_in;
3885 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3886 for (x = 0; x < w; ++x)
3887 {
3888 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3889 * C = Y - 16; D = U - 128; E = V - 128;
3890 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3891 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3892 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3893 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3894 * U and V are shared between the pixels. */
3895 if (!(x & 1)) /* For every even pixel, read new U and V. */
3896 {
3897 d = (int) src_line[1] - 128;
3898 e = (int) src_line[3] - 128;
3899 r2 = 409 * e + 128;
3900 g2 = - 100 * d - 208 * e + 128;
3901 b2 = 516 * d + 128;
3902 }
3903 c2 = 298 * ((int) src_line[0] - 16);
3904 dst_line[x] = 0xff000000
3905 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3906 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3907 | cliptobyte((c2 + b2) >> 8); /* blue */
3908 /* Scale RGB values to 0..255 range,
3909 * then clip them if still not in range (may be negative),
3910 * then shift them within DWORD if necessary. */
3911 src_line += 2;
3912 }
3913 }
3914}
3915
3916static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3917 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3918{
3919 unsigned int x, y;
3920 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3921
3922 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3923
3924 for (y = 0; y < h; ++y)
3925 {
3926 const BYTE *src_line = src + y * pitch_in;
3927 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3928 for (x = 0; x < w; ++x)
3929 {
3930 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3931 * C = Y - 16; D = U - 128; E = V - 128;
3932 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3933 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3934 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3935 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3936 * U and V are shared between the pixels. */
3937 if (!(x & 1)) /* For every even pixel, read new U and V. */
3938 {
3939 d = (int) src_line[1] - 128;
3940 e = (int) src_line[3] - 128;
3941 r2 = 409 * e + 128;
3942 g2 = - 100 * d - 208 * e + 128;
3943 b2 = 516 * d + 128;
3944 }
3945 c2 = 298 * ((int) src_line[0] - 16);
3946 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3947 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3948 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3949 /* Scale RGB values to 0..255 range,
3950 * then clip them if still not in range (may be negative),
3951 * then shift them within DWORD if necessary. */
3952 src_line += 2;
3953 }
3954 }
3955}
3956
3957struct d3dfmt_converter_desc
3958{
3959 enum wined3d_format_id from, to;
3960 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3961};
3962
3963static const struct d3dfmt_converter_desc converters[] =
3964{
3965 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3966 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3967 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3968 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3969 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3970 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3971};
3972
3973static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3974 enum wined3d_format_id to)
3975{
3976 unsigned int i;
3977
3978 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3979 {
3980 if (converters[i].from == from && converters[i].to == to)
3981 return &converters[i];
3982 }
3983
3984 return NULL;
3985}
3986
3987/*****************************************************************************
3988 * surface_convert_format
3989 *
3990 * Creates a duplicate of a surface in a different format. Is used by Blt to
3991 * blit between surfaces with different formats.
3992 *
3993 * Parameters
3994 * source: Source surface
3995 * fmt: Requested destination format
3996 *
3997 *****************************************************************************/
3998static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3999{
4000 struct wined3d_map_desc src_map, dst_map;
4001 const struct d3dfmt_converter_desc *conv;
4002 struct wined3d_surface *ret = NULL;
4003 HRESULT hr;
4004
4005 conv = find_converter(source->resource.format->id, to_fmt);
4006 if (!conv)
4007 {
4008 FIXME("Cannot find a conversion function from format %s to %s.\n",
4009 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
4010 return NULL;
4011 }
4012
4013 /* FIXME: Multisampled conversion? */
4014#ifdef VBOX_WITH_WDDM
4015 if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
4016 to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0,
4017 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret
4018 , NULL, NULL
4019 )))
4020#else
4021 if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
4022 to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0,
4023 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret)))
4024#endif
4025 {
4026 ERR("Failed to create a destination surface for conversion.\n");
4027 return NULL;
4028 }
4029
4030 memset(&src_map, 0, sizeof(src_map));
4031 memset(&dst_map, 0, sizeof(dst_map));
4032
4033 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
4034 {
4035 ERR("Failed to lock the source surface.\n");
4036 wined3d_surface_decref(ret);
4037 return NULL;
4038 }
4039 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
4040 {
4041 ERR("Failed to lock the destination surface.\n");
4042 wined3d_surface_unmap(source);
4043 wined3d_surface_decref(ret);
4044 return NULL;
4045 }
4046
4047 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
4048 source->resource.width, source->resource.height);
4049
4050 wined3d_surface_unmap(ret);
4051 wined3d_surface_unmap(source);
4052
4053 return ret;
4054}
4055
4056static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
4057 unsigned int bpp, UINT pitch, DWORD color)
4058{
4059 BYTE *first;
4060 unsigned int x, y;
4061
4062 /* Do first row */
4063
4064#define COLORFILL_ROW(type) \
4065do { \
4066 type *d = (type *)buf; \
4067 for (x = 0; x < width; ++x) \
4068 d[x] = (type)color; \
4069} while(0)
4070
4071 switch (bpp)
4072 {
4073 case 1:
4074 COLORFILL_ROW(BYTE);
4075 break;
4076
4077 case 2:
4078 COLORFILL_ROW(WORD);
4079 break;
4080
4081 case 3:
4082 {
4083 BYTE *d = buf;
4084 for (x = 0; x < width; ++x, d += 3)
4085 {
4086 d[0] = (color ) & 0xff;
4087 d[1] = (color >> 8) & 0xff;
4088 d[2] = (color >> 16) & 0xff;
4089 }
4090 break;
4091 }
4092 case 4:
4093 COLORFILL_ROW(DWORD);
4094 break;
4095
4096 default:
4097 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
4098 return WINED3DERR_NOTAVAILABLE;
4099 }
4100
4101#undef COLORFILL_ROW
4102
4103 /* Now copy first row. */
4104 first = buf;
4105 for (y = 1; y < height; ++y)
4106 {
4107 buf += pitch;
4108 memcpy(buf, first, width * bpp);
4109 }
4110
4111 return WINED3D_OK;
4112}
4113
4114struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
4115{
4116 return surface_from_resource(resource);
4117}
4118
4119HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
4120{
4121 TRACE("surface %p.\n", surface);
4122
4123 if (!surface->resource.map_count)
4124 {
4125 WARN("Trying to unmap unmapped surface.\n");
4126 return WINEDDERR_NOTLOCKED;
4127 }
4128 --surface->resource.map_count;
4129
4130 surface->surface_ops->surface_unmap(surface);
4131
4132#ifdef VBOX_WITH_WDDM
4133 surface_shrc_unlock(surface);
4134#endif
4135
4136 return WINED3D_OK;
4137}
4138
4139HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
4140 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
4141{
4142 const struct wined3d_format *format = surface->resource.format;
4143
4144 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
4145 surface, map_desc, wine_dbgstr_rect(rect), flags);
4146
4147 if (surface->resource.map_count)
4148 {
4149 WARN("Surface is already mapped.\n");
4150 return WINED3DERR_INVALIDCALL;
4151 }
4152
4153 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
4154 && !surface_check_block_align(surface, rect))
4155 {
4156 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
4157 wine_dbgstr_rect(rect), format->block_width, format->block_height);
4158
4159 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4160 return WINED3DERR_INVALIDCALL;
4161 }
4162
4163#ifdef VBOX_WITH_WDDM
4164 surface_shrc_lock(surface);
4165#endif
4166
4167 ++surface->resource.map_count;
4168
4169 if (!(surface->flags & SFLAG_LOCKABLE))
4170 WARN("Trying to lock unlockable surface.\n");
4171
4172 /* Performance optimization: Count how often a surface is mapped, if it is
4173 * mapped regularly do not throw away the system memory copy. This avoids
4174 * the need to download the surface from OpenGL all the time. The surface
4175 * is still downloaded if the OpenGL texture is changed. */
4176 if (!(surface->flags & SFLAG_DYNLOCK))
4177 {
4178 if (++surface->lockCount > MAXLOCKCOUNT)
4179 {
4180 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
4181 surface->flags |= SFLAG_DYNLOCK;
4182 }
4183 }
4184
4185 surface->surface_ops->surface_map(surface, rect, flags);
4186
4187 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
4188 map_desc->row_pitch = surface->resource.width * format->byte_count;
4189 else
4190 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
4191 map_desc->slice_pitch = 0;
4192
4193 if (!rect)
4194 {
4195 map_desc->data = surface->resource.allocatedMemory;
4196 surface->lockedRect.left = 0;
4197 surface->lockedRect.top = 0;
4198 surface->lockedRect.right = surface->resource.width;
4199 surface->lockedRect.bottom = surface->resource.height;
4200 }
4201 else
4202 {
4203 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
4204 {
4205 /* Compressed textures are block based, so calculate the offset of
4206 * the block that contains the top-left pixel of the locked rectangle. */
4207 map_desc->data = surface->resource.allocatedMemory
4208 + ((rect->top / format->block_height) * map_desc->row_pitch)
4209 + ((rect->left / format->block_width) * format->block_byte_count);
4210 }
4211 else
4212 {
4213 map_desc->data = surface->resource.allocatedMemory
4214 + (map_desc->row_pitch * rect->top)
4215 + (rect->left * format->byte_count);
4216 }
4217 surface->lockedRect.left = rect->left;
4218 surface->lockedRect.top = rect->top;
4219 surface->lockedRect.right = rect->right;
4220 surface->lockedRect.bottom = rect->bottom;
4221 }
4222
4223 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
4224 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
4225
4226 return WINED3D_OK;
4227}
4228
4229HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
4230{
4231 struct wined3d_map_desc map;
4232 HRESULT hr;
4233
4234 TRACE("surface %p, dc %p.\n", surface, dc);
4235
4236 if (surface->flags & SFLAG_USERPTR)
4237 {
4238 ERR("Not supported on surfaces with application-provided memory.\n");
4239 return WINEDDERR_NODC;
4240 }
4241
4242 /* Give more detailed info for ddraw. */
4243 if (surface->flags & SFLAG_DCINUSE)
4244 return WINEDDERR_DCALREADYCREATED;
4245
4246 /* Can't GetDC if the surface is locked. */
4247 if (surface->resource.map_count)
4248 return WINED3DERR_INVALIDCALL;
4249
4250 /* Create a DIB section if there isn't a dc yet. */
4251 if (!surface->hDC)
4252 {
4253 if (surface->flags & SFLAG_CLIENT)
4254 {
4255 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
4256 surface_release_client_storage(surface);
4257 }
4258 hr = surface_create_dib_section(surface);
4259 if (FAILED(hr))
4260 return WINED3DERR_INVALIDCALL;
4261
4262 /* Use the DIB section from now on if we are not using a PBO. */
4263 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4264 {
4265 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4266 surface->resource.heapMemory = NULL;
4267 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4268 }
4269 }
4270
4271 /* Map the surface. */
4272 hr = wined3d_surface_map(surface, &map, NULL, 0);
4273 if (FAILED(hr))
4274 {
4275 ERR("Map failed, hr %#x.\n", hr);
4276 return hr;
4277 }
4278
4279 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4280 * activates the allocatedMemory. */
4281#ifdef VBOX_WITH_WINE_FIX_PBOPSM
4282 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) == (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4283#else
4284 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4285#endif
4286 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4287
4288 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4289 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4290 {
4291 /* GetDC on palettized formats is unsupported in D3D9, and the method
4292 * is missing in D3D8, so this should only be used for DX <=7
4293 * surfaces (with non-device palettes). */
4294 const PALETTEENTRY *pal = NULL;
4295
4296 if (surface->palette)
4297 {
4298 pal = surface->palette->palents;
4299 }
4300 else
4301 {
4302 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4303 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4304
4305 if (dds_primary && dds_primary->palette)
4306 pal = dds_primary->palette->palents;
4307 }
4308
4309 if (pal)
4310 {
4311 RGBQUAD col[256];
4312 unsigned int i;
4313
4314 for (i = 0; i < 256; ++i)
4315 {
4316 col[i].rgbRed = pal[i].peRed;
4317 col[i].rgbGreen = pal[i].peGreen;
4318 col[i].rgbBlue = pal[i].peBlue;
4319 col[i].rgbReserved = 0;
4320 }
4321 SetDIBColorTable(surface->hDC, 0, 256, col);
4322 }
4323 }
4324
4325 surface->flags |= SFLAG_DCINUSE;
4326
4327 *dc = surface->hDC;
4328 TRACE("Returning dc %p.\n", *dc);
4329
4330 return WINED3D_OK;
4331}
4332
4333HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4334{
4335 TRACE("surface %p, dc %p.\n", surface, dc);
4336
4337 if (!(surface->flags & SFLAG_DCINUSE))
4338 return WINEDDERR_NODC;
4339
4340 if (surface->hDC != dc)
4341 {
4342 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4343 dc, surface->hDC);
4344 return WINEDDERR_NODC;
4345 }
4346
4347 /* Copy the contents of the DIB over to the PBO. */
4348#ifdef VBOX_WITH_WINE_FIX_PBOPSM
4349 if (((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) == (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4350#else
4351 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4352#endif
4353 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4354
4355 /* We locked first, so unlock now. */
4356 wined3d_surface_unmap(surface);
4357
4358 surface->flags &= ~SFLAG_DCINUSE;
4359
4360 return WINED3D_OK;
4361}
4362
4363HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4364{
4365 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4366
4367 if (flags)
4368 {
4369 static UINT once;
4370 if (!once++)
4371 FIXME("Ignoring flags %#x.\n", flags);
4372 else
4373 WARN("Ignoring flags %#x.\n", flags);
4374 }
4375
4376 if (surface->swapchain)
4377 {
4378 ERR("Not supported on swapchain surfaces.\n");
4379 return WINEDDERR_NOTFLIPPABLE;
4380 }
4381
4382 /* Flipping is only supported on render targets and overlays. */
4383 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4384 {
4385 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4386 return WINEDDERR_NOTFLIPPABLE;
4387 }
4388
4389 flip_surface(surface, override);
4390
4391 /* Update overlays if they're visible. */
4392 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4393 return surface_draw_overlay(surface);
4394
4395 return WINED3D_OK;
4396}
4397
4398/* Do not call while under the GL lock. */
4399void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4400{
4401 struct wined3d_device *device = surface->resource.device;
4402
4403 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4404
4405 if (surface->container)
4406 {
4407 struct wined3d_texture *texture = surface->container;
4408
4409 TRACE("Passing to container (%p).\n", texture);
4410 texture->texture_ops->texture_preload(texture, srgb);
4411 }
4412 else
4413 {
4414 struct wined3d_context *context;
4415
4416 TRACE("(%p) : About to load surface\n", surface);
4417
4418 /* TODO: Use already acquired context when possible. */
4419 context = context_acquire(device, NULL);
4420
4421 surface_load(surface, srgb == SRGB_SRGB);
4422
4423#ifndef VBOX
4424 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4425 {
4426 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4427 GLclampf tmp;
4428 tmp = 0.9f;
4429 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4430 }
4431#else
4432 /* chromium code on host fails to resolve texture name to texture obj,
4433 * most likely because the texture does not get created until it is bound
4434 * @todo: investigate */
4435#endif
4436 context_release(context);
4437 }
4438}
4439
4440/* Read the framebuffer back into the surface */
4441static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4442{
4443 struct wined3d_device *device = surface->resource.device;
4444 const struct wined3d_gl_info *gl_info;
4445 struct wined3d_context *context;
4446 BYTE *mem;
4447 GLint fmt;
4448 GLint type;
4449 BYTE *row, *top, *bottom;
4450 int i;
4451 BOOL bpp;
4452 RECT local_rect;
4453 BOOL srcIsUpsideDown;
4454 GLint rowLen = 0;
4455 GLint skipPix = 0;
4456 GLint skipRow = 0;
4457
4458 context = context_acquire(device, surface);
4459 context_apply_blit_state(context, device);
4460 gl_info = context->gl_info;
4461
4462 /* Select the correct read buffer, and give some debug output.
4463 * There is no need to keep track of the current read buffer or reset it, every part of the code
4464 * that reads sets the read buffer as desired.
4465 */
4466 if (surface_is_offscreen(surface))
4467 {
4468 /* Mapping the primary render target which is not on a swapchain.
4469 * Read from the back buffer. */
4470 TRACE("Mapping offscreen render target.\n");
4471 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4472 srcIsUpsideDown = TRUE;
4473 }
4474 else
4475 {
4476 /* Onscreen surfaces are always part of a swapchain */
4477 GLenum buffer = surface_get_gl_buffer(surface);
4478 TRACE("Mapping %#x buffer.\n", buffer);
4479 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4480 checkGLcall("glReadBuffer");
4481 srcIsUpsideDown = FALSE;
4482 }
4483
4484 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4485 if (!rect)
4486 {
4487 local_rect.left = 0;
4488 local_rect.top = 0;
4489 local_rect.right = surface->resource.width;
4490 local_rect.bottom = surface->resource.height;
4491 }
4492 else
4493 {
4494 local_rect = *rect;
4495 }
4496 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4497
4498 switch (surface->resource.format->id)
4499 {
4500 case WINED3DFMT_P8_UINT:
4501 {
4502 if (primary_render_target_is_p8(device))
4503 {
4504 /* In case of P8 render targets the index is stored in the alpha component */
4505 fmt = GL_ALPHA;
4506 type = GL_UNSIGNED_BYTE;
4507 mem = dest;
4508 bpp = surface->resource.format->byte_count;
4509 }
4510 else
4511 {
4512 /* GL can't return palettized data, so read ARGB pixels into a
4513 * separate block of memory and convert them into palettized format
4514 * in software. Slow, but if the app means to use palettized render
4515 * targets and locks it...
4516 *
4517 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4518 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4519 * for the color channels when palettizing the colors.
4520 */
4521 fmt = GL_RGB;
4522 type = GL_UNSIGNED_BYTE;
4523 pitch *= 3;
4524 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4525 if (!mem)
4526 {
4527 ERR("Out of memory\n");
4528 return;
4529 }
4530 bpp = surface->resource.format->byte_count * 3;
4531 }
4532 }
4533 break;
4534
4535 default:
4536 mem = dest;
4537 fmt = surface->resource.format->glFormat;
4538 type = surface->resource.format->glType;
4539 bpp = surface->resource.format->byte_count;
4540 }
4541
4542 if (surface->flags & SFLAG_PBO)
4543 {
4544 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4545 checkGLcall("glBindBufferARB");
4546 if (mem)
4547 {
4548 ERR("mem not null for pbo -- unexpected\n");
4549 mem = NULL;
4550 }
4551 }
4552
4553 /* Save old pixel store pack state */
4554 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4555 checkGLcall("glGetIntegerv");
4556 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4557 checkGLcall("glGetIntegerv");
4558 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4559 checkGLcall("glGetIntegerv");
4560
4561 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4562 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4563 checkGLcall("glPixelStorei");
4564 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4565 checkGLcall("glPixelStorei");
4566 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4567 checkGLcall("glPixelStorei");
4568
4569 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4570 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4571 local_rect.right - local_rect.left,
4572 local_rect.bottom - local_rect.top,
4573 fmt, type, mem);
4574 checkGLcall("glReadPixels");
4575
4576 /* Reset previous pixel store pack state */
4577 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4578 checkGLcall("glPixelStorei");
4579 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4580 checkGLcall("glPixelStorei");
4581 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4582 checkGLcall("glPixelStorei");
4583
4584 if (surface->flags & SFLAG_PBO)
4585 {
4586 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4587 checkGLcall("glBindBufferARB");
4588
4589 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4590 * to get a pointer to it and perform the flipping in software. This is a lot
4591 * faster than calling glReadPixels for each line. In case we want more speed
4592 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4593 if (!srcIsUpsideDown)
4594 {
4595 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4596 checkGLcall("glBindBufferARB");
4597
4598 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4599 checkGLcall("glMapBufferARB");
4600 }
4601 }
4602
4603 /* TODO: Merge this with the palettization loop below for P8 targets */
4604 if(!srcIsUpsideDown) {
4605 UINT len, off;
4606 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4607 Flip the lines in software */
4608 len = (local_rect.right - local_rect.left) * bpp;
4609 off = local_rect.left * bpp;
4610
4611 row = HeapAlloc(GetProcessHeap(), 0, len);
4612 if(!row) {
4613 ERR("Out of memory\n");
4614 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4615 HeapFree(GetProcessHeap(), 0, mem);
4616 return;
4617 }
4618
4619 top = mem + pitch * local_rect.top;
4620 bottom = mem + pitch * (local_rect.bottom - 1);
4621 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4622 memcpy(row, top + off, len);
4623 memcpy(top + off, bottom + off, len);
4624 memcpy(bottom + off, row, len);
4625 top += pitch;
4626 bottom -= pitch;
4627 }
4628 HeapFree(GetProcessHeap(), 0, row);
4629
4630 /* Unmap the temp PBO buffer */
4631 if (surface->flags & SFLAG_PBO)
4632 {
4633 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4634 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4635 }
4636 }
4637
4638 context_release(context);
4639
4640 /* For P8 textures we need to perform an inverse palette lookup. This is
4641 * done by searching for a palette index which matches the RGB value.
4642 * Note this isn't guaranteed to work when there are multiple entries for
4643 * the same color but we have no choice. In case of P8 render targets,
4644 * the index is stored in the alpha component so no conversion is needed. */
4645 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4646 {
4647 const PALETTEENTRY *pal = NULL;
4648 DWORD width = pitch / 3;
4649 int x, y, c;
4650
4651 if (surface->palette)
4652 {
4653 pal = surface->palette->palents;
4654 }
4655 else
4656 {
4657 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4658 HeapFree(GetProcessHeap(), 0, mem);
4659 return;
4660 }
4661
4662 for(y = local_rect.top; y < local_rect.bottom; y++) {
4663 for(x = local_rect.left; x < local_rect.right; x++) {
4664 /* start lines pixels */
4665 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4666 const BYTE *green = blue + 1;
4667 const BYTE *red = green + 1;
4668
4669 for(c = 0; c < 256; c++) {
4670 if(*red == pal[c].peRed &&
4671 *green == pal[c].peGreen &&
4672 *blue == pal[c].peBlue)
4673 {
4674 *((BYTE *) dest + y * width + x) = c;
4675 break;
4676 }
4677 }
4678 }
4679 }
4680 HeapFree(GetProcessHeap(), 0, mem);
4681 }
4682}
4683
4684/* Read the framebuffer contents into a texture. Note that this function
4685 * doesn't do any kind of flipping. Using this on an onscreen surface will
4686 * result in a flipped D3D texture. */
4687void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4688{
4689 struct wined3d_device *device = surface->resource.device;
4690 const struct wined3d_gl_info *gl_info;
4691 struct wined3d_context *context;
4692
4693 context = context_acquire(device, surface);
4694 gl_info = context->gl_info;
4695 device_invalidate_state(device, STATE_FRAMEBUFFER);
4696
4697 surface_prepare_texture(surface, context, srgb);
4698 surface_bind_and_dirtify(surface, context, srgb);
4699
4700 TRACE("Reading back offscreen render target %p.\n", surface);
4701
4702 if (surface_is_offscreen(surface))
4703 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4704 else
4705 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4706 checkGLcall("glReadBuffer");
4707
4708 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4709 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4710 checkGLcall("glCopyTexSubImage2D");
4711
4712 context_release(context);
4713}
4714
4715/* Context activation is done by the caller. */
4716static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4717 struct wined3d_context *context, BOOL srgb)
4718{
4719 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4720 enum wined3d_conversion_type convert;
4721 struct wined3d_format format;
4722
4723 if (surface->flags & alloc_flag) return;
4724
4725 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4726 if (convert != WINED3D_CT_NONE || format.convert)
4727 surface->flags |= SFLAG_CONVERTED;
4728 else surface->flags &= ~SFLAG_CONVERTED;
4729
4730 surface_bind_and_dirtify(surface, context, srgb);
4731 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4732 surface->flags |= alloc_flag;
4733}
4734
4735/* Context activation is done by the caller. */
4736void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4737{
4738 if (surface->container)
4739 {
4740 struct wined3d_texture *texture = surface->container;
4741 UINT sub_count = texture->level_count * texture->layer_count;
4742 UINT i;
4743
4744 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4745
4746 for (i = 0; i < sub_count; ++i)
4747 {
4748 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4749 surface_prepare_texture_internal(s, context, srgb);
4750 }
4751
4752 return;
4753 }
4754
4755 surface_prepare_texture_internal(surface, context, srgb);
4756}
4757
4758void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4759{
4760 if (multisample)
4761 {
4762 if (surface->rb_multisample)
4763 return;
4764
4765 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4766 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4767 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4768 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4769 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4770 }
4771 else
4772 {
4773 if (surface->rb_resolved)
4774 return;
4775
4776 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4777 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4778 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4779 surface->pow2Width, surface->pow2Height);
4780 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4781 }
4782}
4783
4784static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4785 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4786{
4787 struct wined3d_device *device = surface->resource.device;
4788 UINT pitch = wined3d_surface_get_pitch(surface);
4789 const struct wined3d_gl_info *gl_info;
4790 struct wined3d_context *context;
4791 RECT local_rect;
4792 UINT w, h;
4793
4794 surface_get_rect(surface, rect, &local_rect);
4795
4796 mem += local_rect.top * pitch + local_rect.left * bpp;
4797 w = local_rect.right - local_rect.left;
4798 h = local_rect.bottom - local_rect.top;
4799
4800 /* Activate the correct context for the render target */
4801 context = context_acquire(device, surface);
4802 context_apply_blit_state(context, device);
4803 gl_info = context->gl_info;
4804
4805 if (!surface_is_offscreen(surface))
4806 {
4807 GLenum buffer = surface_get_gl_buffer(surface);
4808 TRACE("Unlocking %#x buffer.\n", buffer);
4809 context_set_draw_buffer(context, buffer);
4810
4811#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4812 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4813#else
4814 surface_translate_drawable_coords(surface, context->swapchain->win_handle, &local_rect);
4815#endif
4816 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4817 }
4818 else
4819 {
4820 /* Primary offscreen render target */
4821 TRACE("Offscreen render target.\n");
4822 context_set_draw_buffer(context, device->offscreenBuffer);
4823
4824 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4825 }
4826
4827 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4828 checkGLcall("glRasterPos3i");
4829
4830 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4831 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4832
4833 if (surface->flags & SFLAG_PBO)
4834 {
4835 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4836 checkGLcall("glBindBufferARB");
4837 }
4838
4839 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4840 checkGLcall("glDrawPixels");
4841
4842 if (surface->flags & SFLAG_PBO)
4843 {
4844 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4845 checkGLcall("glBindBufferARB");
4846 }
4847
4848 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4849 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4850
4851 if (wined3d_settings.strict_draw_ordering
4852 || (surface->swapchain && surface->swapchain->front_buffer == surface))
4853 gl_info->gl_ops.gl.p_glFlush();
4854
4855 context_release(context);
4856}
4857
4858static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4859{
4860 /* FIXME: Is this really how color keys are supposed to work? I think it
4861 * makes more sense to compare the individual channels. */
4862 return color >= color_key->color_space_low_value
4863 && color <= color_key->color_space_high_value;
4864}
4865
4866void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4867{
4868 const struct wined3d_device *device = surface->resource.device;
4869 const struct wined3d_palette *pal = surface->palette;
4870 BOOL index_in_alpha = FALSE;
4871 unsigned int i;
4872
4873 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4874 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4875 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4876 * duplicate entries. Store the color key in the unused alpha component to speed the
4877 * download up and to make conversion unneeded. */
4878 index_in_alpha = primary_render_target_is_p8(device);
4879
4880 if (!pal)
4881 {
4882 FIXME("No palette set.\n");
4883 if (index_in_alpha)
4884 {
4885 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4886 * there's no palette at this time. */
4887 for (i = 0; i < 256; i++) table[i][3] = i;
4888 }
4889 }
4890 else
4891 {
4892 TRACE("Using surface palette %p\n", pal);
4893 /* Get the surface's palette */
4894 for (i = 0; i < 256; ++i)
4895 {
4896 table[i][0] = pal->palents[i].peRed;
4897 table[i][1] = pal->palents[i].peGreen;
4898 table[i][2] = pal->palents[i].peBlue;
4899
4900 /* When index_in_alpha is set the palette index is stored in the
4901 * alpha component. In case of a readback we can then read
4902 * GL_ALPHA. Color keying is handled in BltOverride using a
4903 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4904 * color key itself is passed to glAlphaFunc in other cases the
4905 * alpha component of pixels that should be masked away is set to 0. */
4906 if (index_in_alpha)
4907 table[i][3] = i;
4908 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4909 table[i][3] = 0x00;
4910 else if (pal->flags & WINEDDPCAPS_ALPHA)
4911 table[i][3] = pal->palents[i].peFlags;
4912 else
4913 table[i][3] = 0xff;
4914 }
4915 }
4916}
4917
4918static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4919 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4920{
4921 const BYTE *source;
4922 BYTE *dest;
4923
4924 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4925 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4926
4927 switch (conversion_type)
4928 {
4929 case WINED3D_CT_NONE:
4930 {
4931 memcpy(dst, src, pitch * height);
4932 break;
4933 }
4934
4935 case WINED3D_CT_PALETTED:
4936 case WINED3D_CT_PALETTED_CK:
4937 {
4938 BYTE table[256][4];
4939 unsigned int x, y;
4940
4941 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4942
4943 for (y = 0; y < height; y++)
4944 {
4945 source = src + pitch * y;
4946 dest = dst + outpitch * y;
4947 /* This is an 1 bpp format, using the width here is fine */
4948 for (x = 0; x < width; x++) {
4949 BYTE color = *source++;
4950 *dest++ = table[color][0];
4951 *dest++ = table[color][1];
4952 *dest++ = table[color][2];
4953 *dest++ = table[color][3];
4954 }
4955 }
4956 }
4957 break;
4958
4959 case WINED3D_CT_CK_565:
4960 {
4961 /* Converting the 565 format in 5551 packed to emulate color-keying.
4962
4963 Note : in all these conversion, it would be best to average the averaging
4964 pixels to get the color of the pixel that will be color-keyed to
4965 prevent 'color bleeding'. This will be done later on if ever it is
4966 too visible.
4967
4968 Note2: Nvidia documents say that their driver does not support alpha + color keying
4969 on the same surface and disables color keying in such a case
4970 */
4971 unsigned int x, y;
4972 const WORD *Source;
4973 WORD *Dest;
4974
4975 TRACE("Color keyed 565\n");
4976
4977 for (y = 0; y < height; y++) {
4978 Source = (const WORD *)(src + y * pitch);
4979 Dest = (WORD *) (dst + y * outpitch);
4980 for (x = 0; x < width; x++ ) {
4981 WORD color = *Source++;
4982 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4983 if (!color_in_range(&surface->src_blt_color_key, color))
4984 *Dest |= 0x0001;
4985 Dest++;
4986 }
4987 }
4988 }
4989 break;
4990
4991 case WINED3D_CT_CK_5551:
4992 {
4993 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4994 unsigned int x, y;
4995 const WORD *Source;
4996 WORD *Dest;
4997 TRACE("Color keyed 5551\n");
4998 for (y = 0; y < height; y++) {
4999 Source = (const WORD *)(src + y * pitch);
5000 Dest = (WORD *) (dst + y * outpitch);
5001 for (x = 0; x < width; x++ ) {
5002 WORD color = *Source++;
5003 *Dest = color;
5004 if (!color_in_range(&surface->src_blt_color_key, color))
5005 *Dest |= (1 << 15);
5006 else
5007 *Dest &= ~(1 << 15);
5008 Dest++;
5009 }
5010 }
5011 }
5012 break;
5013
5014 case WINED3D_CT_CK_RGB24:
5015 {
5016 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
5017 unsigned int x, y;
5018 for (y = 0; y < height; y++)
5019 {
5020 source = src + pitch * y;
5021 dest = dst + outpitch * y;
5022 for (x = 0; x < width; x++) {
5023 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
5024 DWORD dstcolor = color << 8;
5025 if (!color_in_range(&surface->src_blt_color_key, color))
5026 dstcolor |= 0xff;
5027 *(DWORD*)dest = dstcolor;
5028 source += 3;
5029 dest += 4;
5030 }
5031 }
5032 }
5033 break;
5034
5035 case WINED3D_CT_RGB32_888:
5036 {
5037 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
5038 unsigned int x, y;
5039 for (y = 0; y < height; y++)
5040 {
5041 source = src + pitch * y;
5042 dest = dst + outpitch * y;
5043 for (x = 0; x < width; x++) {
5044 DWORD color = 0xffffff & *(const DWORD*)source;
5045 DWORD dstcolor = color << 8;
5046 if (!color_in_range(&surface->src_blt_color_key, color))
5047 dstcolor |= 0xff;
5048 *(DWORD*)dest = dstcolor;
5049 source += 4;
5050 dest += 4;
5051 }
5052 }
5053 }
5054 break;
5055
5056 case WINED3D_CT_CK_ARGB32:
5057 {
5058 unsigned int x, y;
5059 for (y = 0; y < height; ++y)
5060 {
5061 source = src + pitch * y;
5062 dest = dst + outpitch * y;
5063 for (x = 0; x < width; ++x)
5064 {
5065 DWORD color = *(const DWORD *)source;
5066 if (color_in_range(&surface->src_blt_color_key, color))
5067 color &= ~0xff000000;
5068 *(DWORD*)dest = color;
5069 source += 4;
5070 dest += 4;
5071 }
5072 }
5073 }
5074 break;
5075
5076 default:
5077 ERR("Unsupported conversion type %#x.\n", conversion_type);
5078 }
5079 return WINED3D_OK;
5080}
5081
5082void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
5083{
5084 /* Flip the surface contents */
5085 /* Flip the DC */
5086 {
5087 HDC tmp;
5088 tmp = front->hDC;
5089 front->hDC = back->hDC;
5090 back->hDC = tmp;
5091 }
5092
5093 /* Flip the DIBsection */
5094 {
5095 HBITMAP tmp = front->dib.DIBsection;
5096 front->dib.DIBsection = back->dib.DIBsection;
5097 back->dib.DIBsection = tmp;
5098 }
5099
5100 /* Flip the surface data */
5101 {
5102 void* tmp;
5103
5104 tmp = front->dib.bitmap_data;
5105 front->dib.bitmap_data = back->dib.bitmap_data;
5106 back->dib.bitmap_data = tmp;
5107
5108 tmp = front->resource.allocatedMemory;
5109 front->resource.allocatedMemory = back->resource.allocatedMemory;
5110 back->resource.allocatedMemory = tmp;
5111
5112 tmp = front->resource.heapMemory;
5113 front->resource.heapMemory = back->resource.heapMemory;
5114 back->resource.heapMemory = tmp;
5115 }
5116
5117 /* Flip the PBO */
5118 {
5119 GLuint tmp_pbo = front->pbo;
5120 front->pbo = back->pbo;
5121 back->pbo = tmp_pbo;
5122 }
5123
5124 /* Flip the opengl texture */
5125 {
5126 GLuint tmp;
5127
5128 tmp = back->texture_name;
5129 back->texture_name = front->texture_name;
5130 front->texture_name = tmp;
5131
5132 tmp = back->texture_name_srgb;
5133 back->texture_name_srgb = front->texture_name_srgb;
5134 front->texture_name_srgb = tmp;
5135
5136 tmp = back->rb_multisample;
5137 back->rb_multisample = front->rb_multisample;
5138 front->rb_multisample = tmp;
5139
5140 tmp = back->rb_resolved;
5141 back->rb_resolved = front->rb_resolved;
5142 front->rb_resolved = tmp;
5143
5144 resource_unload(&back->resource);
5145 resource_unload(&front->resource);
5146 }
5147
5148 {
5149 DWORD tmp_flags = back->flags;
5150 back->flags = front->flags;
5151 front->flags = tmp_flags;
5152 }
5153}
5154
5155/* Does a direct frame buffer -> texture copy. Stretching is done with single
5156 * pixel copy calls. */
5157static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5158 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5159{
5160 struct wined3d_device *device = dst_surface->resource.device;
5161 const struct wined3d_gl_info *gl_info;
5162 float xrel, yrel;
5163 struct wined3d_context *context;
5164 BOOL upsidedown = FALSE;
5165 RECT dst_rect = *dst_rect_in;
5166 GLenum dst_target;
5167
5168 if (dst_surface->container)
5169 dst_target = dst_surface->container->target;
5170 else
5171 dst_target = dst_surface->texture_target;
5172
5173 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5174 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5175 */
5176 if(dst_rect.top > dst_rect.bottom) {
5177 UINT tmp = dst_rect.bottom;
5178 dst_rect.bottom = dst_rect.top;
5179 dst_rect.top = tmp;
5180 upsidedown = TRUE;
5181 }
5182
5183 context = context_acquire(device, src_surface);
5184 gl_info = context->gl_info;
5185 context_apply_blit_state(context, device);
5186 surface_internal_preload(dst_surface, SRGB_RGB);
5187
5188 /* Bind the target texture */
5189 context_bind_texture(context, dst_target, dst_surface->texture_name);
5190 if (surface_is_offscreen(src_surface))
5191 {
5192 TRACE("Reading from an offscreen target\n");
5193 upsidedown = !upsidedown;
5194 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5195 }
5196 else
5197 {
5198 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5199 }
5200 checkGLcall("glReadBuffer");
5201
5202 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
5203 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
5204
5205 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5206 {
5207 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
5208
5209 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
5210 ERR("Texture filtering not supported in direct blit.\n");
5211 }
5212 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
5213 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5214 {
5215 ERR("Texture filtering not supported in direct blit\n");
5216 }
5217
5218 if (upsidedown
5219 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5220 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5221 {
5222 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
5223 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5224 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
5225 src_rect->left, src_surface->resource.height - src_rect->bottom,
5226 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5227 }
5228 else
5229 {
5230 LONG row;
5231 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
5232 /* I have to process this row by row to swap the image,
5233 * otherwise it would be upside down, so stretching in y direction
5234 * doesn't cost extra time
5235 *
5236 * However, stretching in x direction can be avoided if not necessary
5237 */
5238 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
5239 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5240 {
5241 /* Well, that stuff works, but it's very slow.
5242 * find a better way instead
5243 */
5244 LONG col;
5245
5246 for (col = dst_rect.left; col < dst_rect.right; ++col)
5247 {
5248 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5249 dst_rect.left + col /* x offset */, row /* y offset */,
5250 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
5251 }
5252 }
5253 else
5254 {
5255 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5256 dst_rect.left /* x offset */, row /* y offset */,
5257 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5258 }
5259 }
5260 }
5261 checkGLcall("glCopyTexSubImage2D");
5262
5263 context_release(context);
5264
5265 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5266 * path is never entered
5267 */
5268 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5269}
5270
5271/* Uses the hardware to stretch and flip the image */
5272static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5273 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5274{
5275 struct wined3d_device *device = dst_surface->resource.device;
5276 GLuint src, backup = 0;
5277 float left, right, top, bottom; /* Texture coordinates */
5278 UINT fbwidth = src_surface->resource.width;
5279 UINT fbheight = src_surface->resource.height;
5280 const struct wined3d_gl_info *gl_info;
5281 struct wined3d_context *context;
5282 GLenum drawBuffer = GL_BACK;
5283 GLenum texture_target;
5284 BOOL noBackBufferBackup;
5285 BOOL src_offscreen;
5286 BOOL upsidedown = FALSE;
5287 RECT dst_rect = *dst_rect_in;
5288
5289 TRACE("Using hwstretch blit\n");
5290 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5291 context = context_acquire(device, src_surface);
5292 gl_info = context->gl_info;
5293 context_apply_blit_state(context, device);
5294 surface_internal_preload(dst_surface, SRGB_RGB);
5295
5296 src_offscreen = surface_is_offscreen(src_surface);
5297 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5298 if (!noBackBufferBackup && !src_surface->texture_name)
5299 {
5300 /* Get it a description */
5301 surface_internal_preload(src_surface, SRGB_RGB);
5302 }
5303
5304 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5305 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5306 */
5307 if (context->aux_buffers >= 2)
5308 {
5309 /* Got more than one aux buffer? Use the 2nd aux buffer */
5310 drawBuffer = GL_AUX1;
5311 }
5312 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5313 {
5314 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5315 drawBuffer = GL_AUX0;
5316 }
5317
5318 if (noBackBufferBackup)
5319 {
5320 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5321 checkGLcall("glGenTextures");
5322 context_bind_texture(context, GL_TEXTURE_2D, backup);
5323 texture_target = GL_TEXTURE_2D;
5324 }
5325 else
5326 {
5327 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5328 * we are reading from the back buffer, the backup can be used as source texture
5329 */
5330 texture_target = src_surface->texture_target;
5331 context_bind_texture(context, texture_target, src_surface->texture_name);
5332 gl_info->gl_ops.gl.p_glEnable(texture_target);
5333 checkGLcall("glEnable(texture_target)");
5334
5335 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5336 src_surface->flags &= ~SFLAG_INTEXTURE;
5337 }
5338
5339 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5340 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5341 */
5342 if(dst_rect.top > dst_rect.bottom) {
5343 UINT tmp = dst_rect.bottom;
5344 dst_rect.bottom = dst_rect.top;
5345 dst_rect.top = tmp;
5346 upsidedown = TRUE;
5347 }
5348
5349 if (src_offscreen)
5350 {
5351 TRACE("Reading from an offscreen target\n");
5352 upsidedown = !upsidedown;
5353 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5354 }
5355 else
5356 {
5357 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5358 }
5359
5360 /* TODO: Only back up the part that will be overwritten */
5361 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5362
5363 checkGLcall("glCopyTexSubImage2D");
5364
5365 /* No issue with overriding these - the sampler is dirty due to blit usage */
5366 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5367 wined3d_gl_mag_filter(magLookup, filter));
5368 checkGLcall("glTexParameteri");
5369 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5370 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5371 checkGLcall("glTexParameteri");
5372
5373 if (!src_surface->swapchain || src_surface == src_surface->swapchain->back_buffers[0])
5374 {
5375 src = backup ? backup : src_surface->texture_name;
5376 }
5377 else
5378 {
5379 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5380 checkGLcall("glReadBuffer(GL_FRONT)");
5381
5382 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5383 checkGLcall("glGenTextures(1, &src)");
5384 context_bind_texture(context, GL_TEXTURE_2D, src);
5385
5386 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5387 * out for power of 2 sizes
5388 */
5389 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5390 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5391 checkGLcall("glTexImage2D");
5392 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5393
5394 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5395 checkGLcall("glTexParameteri");
5396 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5397 checkGLcall("glTexParameteri");
5398
5399 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5400 checkGLcall("glReadBuffer(GL_BACK)");
5401
5402 if (texture_target != GL_TEXTURE_2D)
5403 {
5404 gl_info->gl_ops.gl.p_glDisable(texture_target);
5405 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5406 texture_target = GL_TEXTURE_2D;
5407 }
5408 }
5409 checkGLcall("glEnd and previous");
5410
5411 left = src_rect->left;
5412 right = src_rect->right;
5413
5414 if (!upsidedown)
5415 {
5416 top = src_surface->resource.height - src_rect->top;
5417 bottom = src_surface->resource.height - src_rect->bottom;
5418 }
5419 else
5420 {
5421 top = src_surface->resource.height - src_rect->bottom;
5422 bottom = src_surface->resource.height - src_rect->top;
5423 }
5424
5425 if (src_surface->flags & SFLAG_NORMCOORD)
5426 {
5427 left /= src_surface->pow2Width;
5428 right /= src_surface->pow2Width;
5429 top /= src_surface->pow2Height;
5430 bottom /= src_surface->pow2Height;
5431 }
5432
5433 /* draw the source texture stretched and upside down. The correct surface is bound already */
5434 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5435 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5436
5437 context_set_draw_buffer(context, drawBuffer);
5438 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5439
5440 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5441 /* bottom left */
5442 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5443 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5444
5445 /* top left */
5446 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5447 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5448
5449 /* top right */
5450 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5451 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5452
5453 /* bottom right */
5454 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5455 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5456 gl_info->gl_ops.gl.p_glEnd();
5457 checkGLcall("glEnd and previous");
5458
5459 if (texture_target != dst_surface->texture_target)
5460 {
5461 gl_info->gl_ops.gl.p_glDisable(texture_target);
5462 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5463 texture_target = dst_surface->texture_target;
5464 }
5465
5466 /* Now read the stretched and upside down image into the destination texture */
5467 context_bind_texture(context, texture_target, dst_surface->texture_name);
5468 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5469 0,
5470 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5471 0, 0, /* We blitted the image to the origin */
5472 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5473 checkGLcall("glCopyTexSubImage2D");
5474
5475 if (drawBuffer == GL_BACK)
5476 {
5477 /* Write the back buffer backup back. */
5478 if (backup)
5479 {
5480 if (texture_target != GL_TEXTURE_2D)
5481 {
5482 gl_info->gl_ops.gl.p_glDisable(texture_target);
5483 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5484 texture_target = GL_TEXTURE_2D;
5485 }
5486 context_bind_texture(context, GL_TEXTURE_2D, backup);
5487 }
5488 else
5489 {
5490 if (texture_target != src_surface->texture_target)
5491 {
5492 gl_info->gl_ops.gl.p_glDisable(texture_target);
5493 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5494 texture_target = src_surface->texture_target;
5495 }
5496 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5497 }
5498
5499 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5500 /* top left */
5501 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5502 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5503
5504 /* bottom left */
5505 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5506 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5507
5508 /* bottom right */
5509 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5510 (float)fbheight / (float)src_surface->pow2Height);
5511 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5512
5513 /* top right */
5514 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5515 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5516 gl_info->gl_ops.gl.p_glEnd();
5517 }
5518 gl_info->gl_ops.gl.p_glDisable(texture_target);
5519 checkGLcall("glDisable(texture_target)");
5520
5521 /* Cleanup */
5522 if (src != src_surface->texture_name && src != backup)
5523 {
5524 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5525 checkGLcall("glDeleteTextures(1, &src)");
5526 }
5527 if (backup)
5528 {
5529 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5530 checkGLcall("glDeleteTextures(1, &backup)");
5531 }
5532
5533 if (wined3d_settings.strict_draw_ordering)
5534 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5535
5536 context_release(context);
5537
5538 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5539 * path is never entered
5540 */
5541 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5542}
5543
5544/* Front buffer coordinates are always full screen coordinates, but our GL
5545 * drawable is limited to the window's client area. The sysmem and texture
5546 * copies do have the full screen size. Note that GL has a bottom-left
5547 * origin, while D3D has a top-left origin. */
5548void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5549{
5550 UINT drawable_height;
5551 if (surface->swapchain && surface == surface->swapchain->front_buffer)
5552 {
5553#ifndef VBOX_WITH_WINE_FIXES
5554 POINT offset = {0, 0};
5555 RECT windowsize;
5556
5557 ScreenToClient(window, &offset);
5558 OffsetRect(rect, offset.x, offset.y);
5559
5560 GetClientRect(window, &windowsize);
5561 drawable_height = windowsize.bottom - windowsize.top;
5562#else
5563# ifdef VBOX_WINE_STRICT
5564 ERR("should not be here!");
5565# else
5566 WARN("should not be here!");
5567# endif
5568 drawable_height = surface->resource.height;
5569#endif
5570 }
5571 else
5572 {
5573 drawable_height = surface->resource.height;
5574 }
5575
5576 rect->top = drawable_height - rect->top;
5577 rect->bottom = drawable_height - rect->bottom;
5578}
5579
5580static void surface_blt_to_drawable(const struct wined3d_device *device,
5581 enum wined3d_texture_filter_type filter, BOOL color_key,
5582 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5583 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5584{
5585 const struct wined3d_gl_info *gl_info;
5586 struct wined3d_context *context;
5587 RECT src_rect, dst_rect;
5588
5589 src_rect = *src_rect_in;
5590 dst_rect = *dst_rect_in;
5591
5592 /* Make sure the surface is up-to-date. This should probably use
5593 * surface_load_location() and worry about the destination surface too,
5594 * unless we're overwriting it completely. */
5595 surface_internal_preload(src_surface, SRGB_RGB);
5596
5597 /* Activate the destination context, set it up for blitting */
5598 context = context_acquire(device, dst_surface);
5599 gl_info = context->gl_info;
5600 context_apply_blit_state(context, device);
5601
5602 if (!surface_is_offscreen(dst_surface))
5603#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
5604 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5605#else
5606 surface_translate_drawable_coords(dst_surface, context->swapchain->win_handle, &dst_rect);
5607#endif
5608
5609 device->blitter->set_shader(device->blit_priv, context, src_surface);
5610
5611 if (color_key)
5612 {
5613 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5614 checkGLcall("glEnable(GL_ALPHA_TEST)");
5615
5616 /* When the primary render target uses P8, the alpha component
5617 * contains the palette index. Which means that the colorkey is one of
5618 * the palette entries. In other cases pixels that should be masked
5619 * away have alpha set to 0. */
5620 if (primary_render_target_is_p8(device))
5621 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5622 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5623 else
5624 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5625 checkGLcall("glAlphaFunc");
5626 }
5627 else
5628 {
5629 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5630 checkGLcall("glDisable(GL_ALPHA_TEST)");
5631 }
5632
5633 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5634
5635 if (color_key)
5636 {
5637 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5638 checkGLcall("glDisable(GL_ALPHA_TEST)");
5639 }
5640
5641 /* Leave the opengl state valid for blitting */
5642 device->blitter->unset_shader(context->gl_info);
5643
5644 if (wined3d_settings.strict_draw_ordering
5645 || (dst_surface->swapchain && dst_surface->swapchain->front_buffer == dst_surface))
5646 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5647
5648 context_release(context);
5649}
5650
5651/* Do not call while under the GL lock. */
5652HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5653{
5654 struct wined3d_device *device = s->resource.device;
5655 const struct blit_shader *blitter;
5656
5657 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5658 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5659 if (!blitter)
5660 {
5661 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5662 return WINED3DERR_INVALIDCALL;
5663 }
5664
5665 return blitter->color_fill(device, s, rect, color);
5666}
5667
5668/* Do not call while under the GL lock. */
5669static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5670 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5671 enum wined3d_texture_filter_type filter)
5672{
5673 struct wined3d_device *device = dst_surface->resource.device;
5674 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5675 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
5676
5677 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5678 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5679 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5680
5681 /* Get the swapchain. One of the surfaces has to be a primary surface */
5682 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5683 {
5684 WARN("Destination is in sysmem, rejecting gl blt\n");
5685 return WINED3DERR_INVALIDCALL;
5686 }
5687
5688 dst_swapchain = dst_surface->swapchain;
5689
5690 if (src_surface)
5691 {
5692 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5693 {
5694 WARN("Src is in sysmem, rejecting gl blt\n");
5695 return WINED3DERR_INVALIDCALL;
5696 }
5697
5698 src_swapchain = src_surface->swapchain;
5699 }
5700 else
5701 {
5702 src_swapchain = NULL;
5703 }
5704
5705 /* Early sort out of cases where no render target is used */
5706 if (!dst_swapchain && !src_swapchain
5707 && src_surface != device->fb.render_targets[0]
5708 && dst_surface != device->fb.render_targets[0])
5709 {
5710 TRACE("No surface is render target, not using hardware blit.\n");
5711 return WINED3DERR_INVALIDCALL;
5712 }
5713
5714 /* No destination color keying supported */
5715 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5716 {
5717 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5718 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5719 return WINED3DERR_INVALIDCALL;
5720 }
5721
5722 if (dst_swapchain && dst_swapchain == src_swapchain)
5723 {
5724 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5725 return WINED3DERR_INVALIDCALL;
5726 }
5727
5728 if (dst_swapchain && src_swapchain)
5729 {
5730 FIXME("Implement hardware blit between two different swapchains\n");
5731 return WINED3DERR_INVALIDCALL;
5732 }
5733
5734 if (dst_swapchain)
5735 {
5736 /* Handled with regular texture -> swapchain blit */
5737 if (src_surface == device->fb.render_targets[0])
5738 TRACE("Blit from active render target to a swapchain\n");
5739 }
5740 else if (src_swapchain && dst_surface == device->fb.render_targets[0])
5741 {
5742 FIXME("Implement blit from a swapchain to the active render target\n");
5743 return WINED3DERR_INVALIDCALL;
5744 }
5745
5746 if ((src_swapchain || src_surface == device->fb.render_targets[0]) && !dst_swapchain)
5747 {
5748 /* Blit from render target to texture */
5749 BOOL stretchx;
5750
5751 /* P8 read back is not implemented */
5752 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5753 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5754 {
5755 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5756 return WINED3DERR_INVALIDCALL;
5757 }
5758
5759 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5760 {
5761 TRACE("Color keying not supported by frame buffer to texture blit\n");
5762 return WINED3DERR_INVALIDCALL;
5763 /* Destination color key is checked above */
5764 }
5765
5766 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5767 stretchx = TRUE;
5768 else
5769 stretchx = FALSE;
5770
5771 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5772 * flip the image nor scale it.
5773 *
5774 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5775 * -> If the app wants a image width an unscaled width, copy it line per line
5776 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5777 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5778 * back buffer. This is slower than reading line per line, thus not used for flipping
5779 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5780 * pixel by pixel. */
5781 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5782 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5783 {
5784 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5785 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5786 }
5787 else
5788 {
5789 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5790 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5791 }
5792
5793 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5794 {
5795 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5796 dst_surface->resource.allocatedMemory = NULL;
5797 dst_surface->resource.heapMemory = NULL;
5798 }
5799 else
5800 {
5801 dst_surface->flags &= ~SFLAG_INSYSMEM;
5802 }
5803
5804 return WINED3D_OK;
5805 }
5806 else if (src_surface)
5807 {
5808 /* Blit from offscreen surface to render target */
5809 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5810 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5811
5812 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5813
5814 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5815 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5816 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5817 {
5818 FIXME("Unsupported blit operation falling back to software\n");
5819 return WINED3DERR_INVALIDCALL;
5820 }
5821
5822 /* Color keying: Check if we have to do a color keyed blt,
5823 * and if not check if a color key is activated.
5824 *
5825 * Just modify the color keying parameters in the surface and restore them afterwards
5826 * The surface keeps track of the color key last used to load the opengl surface.
5827 * PreLoad will catch the change to the flags and color key and reload if necessary.
5828 */
5829 if (flags & WINEDDBLT_KEYSRC)
5830 {
5831 /* Use color key from surface */
5832 }
5833 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5834 {
5835 /* Use color key from DDBltFx */
5836 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5837 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5838 }
5839 else
5840 {
5841 /* Do not use color key */
5842 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5843 }
5844
5845 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5846 src_surface, src_rect, dst_surface, dst_rect);
5847
5848 /* Restore the color key parameters */
5849 src_surface->CKeyFlags = oldCKeyFlags;
5850 src_surface->src_blt_color_key = old_blt_key;
5851
5852 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5853
5854 return WINED3D_OK;
5855 }
5856
5857 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5858 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5859 return WINED3DERR_INVALIDCALL;
5860}
5861
5862/* Context activation is done by the caller. */
5863static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5864 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5865{
5866 struct wined3d_device *device = surface->resource.device;
5867 const struct wined3d_gl_info *gl_info = context->gl_info;
5868 GLint compare_mode = GL_NONE;
5869 struct blt_info info;
5870 GLint old_binding = 0;
5871 RECT rect;
5872
5873 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5874
5875 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5876 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5877 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5878 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5879 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5880 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5881 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5882 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5883 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5884 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5885 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5886
5887 SetRect(&rect, 0, h, w, 0);
5888 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5889 context_active_texture(context, context->gl_info, 0);
5890 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5891 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5892 if (gl_info->supported[ARB_SHADOW])
5893 {
5894 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5895 if (compare_mode != GL_NONE)
5896 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5897 }
5898
5899 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5900 gl_info, info.tex_type, &surface->ds_current_size);
5901
5902 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5903 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5904 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5905 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5906 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5907 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5908 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5909 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5910 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5911 gl_info->gl_ops.gl.p_glEnd();
5912
5913 if (compare_mode != GL_NONE)
5914 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5915 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5916
5917 gl_info->gl_ops.gl.p_glPopAttrib();
5918
5919 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5920}
5921
5922void surface_modify_ds_location(struct wined3d_surface *surface,
5923 DWORD location, UINT w, UINT h)
5924{
5925 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5926
5927 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5928 FIXME("Invalid location (%#x) specified.\n", location);
5929
5930 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5931 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5932 {
5933 if (surface->container)
5934 {
5935 TRACE("Passing to container.\n");
5936 wined3d_texture_set_dirty(surface->container, TRUE);
5937 }
5938 }
5939
5940 surface->ds_current_size.cx = w;
5941 surface->ds_current_size.cy = h;
5942 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5943 surface->flags |= location;
5944}
5945
5946/* Context activation is done by the caller. */
5947void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5948{
5949 const struct wined3d_gl_info *gl_info = context->gl_info;
5950 struct wined3d_device *device = surface->resource.device;
5951 GLsizei w, h;
5952
5953 TRACE("surface %p, new location %#x.\n", surface, location);
5954
5955 /* TODO: Make this work for modes other than FBO */
5956 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5957
5958 if (!(surface->flags & location))
5959 {
5960 w = surface->ds_current_size.cx;
5961 h = surface->ds_current_size.cy;
5962 surface->ds_current_size.cx = 0;
5963 surface->ds_current_size.cy = 0;
5964 }
5965 else
5966 {
5967 w = surface->resource.width;
5968 h = surface->resource.height;
5969 }
5970
5971 if (surface->ds_current_size.cx == surface->resource.width
5972 && surface->ds_current_size.cy == surface->resource.height)
5973 {
5974 TRACE("Location (%#x) is already up to date.\n", location);
5975 return;
5976 }
5977
5978 if (surface->current_renderbuffer)
5979 {
5980 FIXME("Not supported with fixed up depth stencil.\n");
5981 return;
5982 }
5983
5984 if (surface->flags & SFLAG_DISCARDED)
5985 {
5986 TRACE("Surface was discarded, no need copy data.\n");
5987 switch (location)
5988 {
5989 case SFLAG_INTEXTURE:
5990 surface_prepare_texture(surface, context, FALSE);
5991 break;
5992 case SFLAG_INRB_MULTISAMPLE:
5993 surface_prepare_rb(surface, gl_info, TRUE);
5994 break;
5995 case SFLAG_INDRAWABLE:
5996 /* Nothing to do */
5997 break;
5998 default:
5999 FIXME("Unhandled location %#x\n", location);
6000 }
6001 surface->flags &= ~SFLAG_DISCARDED;
6002 surface->flags |= location;
6003 surface->ds_current_size.cx = surface->resource.width;
6004 surface->ds_current_size.cy = surface->resource.height;
6005 return;
6006 }
6007
6008 if (!(surface->flags & SFLAG_LOCATIONS))
6009 {
6010 FIXME("No up to date depth stencil location.\n");
6011 surface->flags |= location;
6012 surface->ds_current_size.cx = surface->resource.width;
6013 surface->ds_current_size.cy = surface->resource.height;
6014 return;
6015 }
6016
6017 if (location == SFLAG_INTEXTURE)
6018 {
6019 GLint old_binding = 0;
6020 GLenum bind_target;
6021
6022 /* The render target is allowed to be smaller than the depth/stencil
6023 * buffer, so the onscreen depth/stencil buffer is potentially smaller
6024 * than the offscreen surface. Don't overwrite the offscreen surface
6025 * with undefined data. */
6026 w = min(w, context->swapchain->desc.backbuffer_width);
6027 h = min(h, context->swapchain->desc.backbuffer_height);
6028
6029 TRACE("Copying onscreen depth buffer to depth texture.\n");
6030
6031 if (!device->depth_blt_texture)
6032 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
6033
6034 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
6035 * directly on the FBO texture. That's because we need to flip. */
6036 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6037 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
6038 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
6039 {
6040 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6041 bind_target = GL_TEXTURE_RECTANGLE_ARB;
6042 }
6043 else
6044 {
6045 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6046 bind_target = GL_TEXTURE_2D;
6047 }
6048 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
6049 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
6050 * internal format, because the internal format might include stencil
6051 * data. In principle we should copy stencil data as well, but unless
6052 * the driver supports stencil export it's hard to do, and doesn't
6053 * seem to be needed in practice. If the hardware doesn't support
6054 * writing stencil data, the glCopyTexImage2D() call might trigger
6055 * software fallbacks. */
6056 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
6057 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6058 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6059 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6060 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6061 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
6062 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6063 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
6064
6065 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6066 NULL, surface, SFLAG_INTEXTURE);
6067 context_set_draw_buffer(context, GL_NONE);
6068
6069 /* Do the actual blit */
6070 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
6071 checkGLcall("depth_blt");
6072
6073 context_invalidate_state(context, STATE_FRAMEBUFFER);
6074
6075 if (wined3d_settings.strict_draw_ordering)
6076 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
6077 }
6078 else if (location == SFLAG_INDRAWABLE)
6079 {
6080 TRACE("Copying depth texture to onscreen depth buffer.\n");
6081
6082 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6083 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
6084 surface_depth_blt(surface, context, surface->texture_name,
6085 0, surface->pow2Height - h, w, h, surface->texture_target);
6086 checkGLcall("depth_blt");
6087
6088 context_invalidate_state(context, STATE_FRAMEBUFFER);
6089
6090 if (wined3d_settings.strict_draw_ordering)
6091 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
6092 }
6093 else
6094 {
6095 ERR("Invalid location (%#x) specified.\n", location);
6096 }
6097
6098 surface->flags |= location;
6099 surface->ds_current_size.cx = surface->resource.width;
6100 surface->ds_current_size.cy = surface->resource.height;
6101}
6102
6103void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
6104{
6105 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
6106 struct wined3d_surface *overlay;
6107
6108 TRACE("surface %p, location %s, persistent %#x.\n",
6109 surface, debug_surflocation(location), persistent);
6110
6111 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
6112 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6113 && (location & SFLAG_INDRAWABLE))
6114 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
6115
6116 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6117 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6118 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6119
6120 if (persistent)
6121 {
6122 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
6123 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
6124 {
6125 if (surface->container)
6126 {
6127 TRACE("Passing to container.\n");
6128 wined3d_texture_set_dirty(surface->container, TRUE);
6129 }
6130 }
6131
6132#ifdef VBOX_WITH_WDDM
6133 {
6134 /* sometimes wine can call ModifyLocation(SFLAG_INTEXTURE, TRUE) for surfaces that do not yet have
6135 * ogl texture backend assigned, e.g. when doing ColorFill right after surface creation
6136 * to prevent wine state breakage that could occur later on in that case, we check
6137 * whether tex gen is needed here and generate it accordingly */
6138 if (!surface->texture_name)
6139 {
6140 Assert(!(surface->flags & SFLAG_INTEXTURE));
6141 if (location & SFLAG_INTEXTURE)
6142 {
6143 Assert(0);
6144// struct wined3d_context *context = NULL;
6145// IWineD3DDeviceImpl *device = This->resource.device;
6146// const struct wined3d_gl_info *gl_info;
6147//
6148// if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6149// gl_info = context->gl_info;
6150//
6151// surface_prepare_texture(This, gl_info, FALSE);
6152//
6153// if (context) context_release(context);
6154 }
6155 }
6156
6157 if (!surface->texture_name_srgb)
6158 {
6159 Assert(!(surface->flags & SFLAG_INSRGBTEX));
6160 if (location & SFLAG_INSRGBTEX)
6161 {
6162 Assert(0);
6163// struct wined3d_context *context = NULL;
6164// IWineD3DDeviceImpl *device = This->resource.device;
6165// const struct wined3d_gl_info *gl_info;
6166//
6167// if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6168// gl_info = context->gl_info;
6169//
6170// surface_prepare_texture(This, gl_info, TRUE);
6171//
6172// if (context) context_release(context);
6173 }
6174 }
6175 }
6176#endif
6177
6178 surface->flags &= ~SFLAG_LOCATIONS;
6179 surface->flags |= location;
6180
6181 /* Redraw emulated overlays, if any */
6182 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
6183 {
6184 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
6185 {
6186 surface_draw_overlay(overlay);
6187 }
6188 }
6189 }
6190 else
6191 {
6192 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
6193 {
6194 if (surface->container)
6195 {
6196 TRACE("Passing to container\n");
6197 wined3d_texture_set_dirty(surface->container, TRUE);
6198 }
6199 }
6200 surface->flags &= ~location;
6201 }
6202
6203#ifdef VBOX_WITH_WDDM
6204 if(VBOXSHRC_IS_SHARED_UNLOCKED(surface)) {
6205 /* with the shared resource only texture can be considered valid
6206 * to make sure changes done to the resource in the other device context are visible
6207 * because the resource contents is shared via texture.
6208 * This is why we ensure texture location is the one and only which is always valid */
6209 if(!(surface->flags & SFLAG_INTEXTURE)) {
6210 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6211 } else {
6212 surface->flags &= ~SFLAG_LOCATIONS;
6213 surface->flags |= SFLAG_INTEXTURE;
6214 }
6215 }
6216 else if (surface->flags & SFLAG_CLIENTMEM)
6217 {
6218 if(!(surface->flags & SFLAG_INSYSMEM)) {
6219 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
6220 } else {
6221 surface->flags &= ~SFLAG_LOCATIONS;
6222 surface->flags |= SFLAG_INSYSMEM;
6223 }
6224 }
6225#endif
6226
6227
6228 if (!(surface->flags & SFLAG_LOCATIONS))
6229 {
6230 ERR("Surface %p does not have any up to date location.\n", surface);
6231 }
6232}
6233
6234static DWORD resource_access_from_location(DWORD location)
6235{
6236 switch (location)
6237 {
6238 case SFLAG_INSYSMEM:
6239 return WINED3D_RESOURCE_ACCESS_CPU;
6240
6241 case SFLAG_INDRAWABLE:
6242 case SFLAG_INSRGBTEX:
6243 case SFLAG_INTEXTURE:
6244 case SFLAG_INRB_MULTISAMPLE:
6245 case SFLAG_INRB_RESOLVED:
6246 return WINED3D_RESOURCE_ACCESS_GPU;
6247
6248 default:
6249 FIXME("Unhandled location %#x.\n", location);
6250 return 0;
6251 }
6252}
6253
6254static void surface_load_sysmem(struct wined3d_surface *surface,
6255 const struct wined3d_gl_info *gl_info, const RECT *rect)
6256{
6257 surface_prepare_system_memory(surface);
6258
6259 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
6260 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6261
6262 /* Download the surface to system memory. */
6263 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
6264 {
6265 struct wined3d_device *device = surface->resource.device;
6266 struct wined3d_context *context;
6267
6268 /* TODO: Use already acquired context when possible. */
6269 context = context_acquire(device, NULL);
6270
6271 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
6272 surface_download_data(surface, gl_info);
6273
6274 context_release(context);
6275
6276 return;
6277 }
6278
6279 if (surface->flags & SFLAG_INDRAWABLE)
6280 {
6281 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
6282 wined3d_surface_get_pitch(surface));
6283 return;
6284 }
6285
6286 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
6287 surface, surface->flags & SFLAG_LOCATIONS);
6288}
6289
6290static HRESULT surface_load_drawable(struct wined3d_surface *surface,
6291 const struct wined3d_gl_info *gl_info, const RECT *rect)
6292{
6293 struct wined3d_device *device = surface->resource.device;
6294 enum wined3d_conversion_type convert;
6295 struct wined3d_format format;
6296 UINT byte_count;
6297 BYTE *mem;
6298
6299 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
6300 {
6301 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
6302 return WINED3DERR_INVALIDCALL;
6303 }
6304
6305 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
6306 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6307
6308 if (surface->flags & SFLAG_INTEXTURE)
6309 {
6310 RECT r;
6311
6312 surface_get_rect(surface, rect, &r);
6313 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
6314
6315 return WINED3D_OK;
6316 }
6317
6318 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
6319 {
6320 /* This needs colorspace conversion from sRGB to RGB. We take the slow
6321 * path through sysmem. */
6322 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6323 }
6324
6325 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6326
6327 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6328 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6329 * called. */
6330 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6331 {
6332 struct wined3d_context *context;
6333
6334 TRACE("Removing the pbo attached to surface %p.\n", surface);
6335
6336 /* TODO: Use already acquired context when possible. */
6337 context = context_acquire(device, NULL);
6338
6339 surface_remove_pbo(surface, gl_info);
6340
6341 context_release(context);
6342 }
6343
6344 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6345 {
6346 UINT height = surface->resource.height;
6347 UINT width = surface->resource.width;
6348 UINT src_pitch, dst_pitch;
6349
6350 byte_count = format.conv_byte_count;
6351 src_pitch = wined3d_surface_get_pitch(surface);
6352
6353 /* Stick to the alignment for the converted surface too, makes it
6354 * easier to load the surface. */
6355 dst_pitch = width * byte_count;
6356 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6357
6358 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6359 {
6360 ERR("Out of memory (%u).\n", dst_pitch * height);
6361 return E_OUTOFMEMORY;
6362 }
6363
6364 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6365 src_pitch, width, height, dst_pitch, convert, surface);
6366
6367 surface->flags |= SFLAG_CONVERTED;
6368 }
6369 else
6370 {
6371 surface->flags &= ~SFLAG_CONVERTED;
6372 mem = surface->resource.allocatedMemory;
6373 byte_count = format.byte_count;
6374 }
6375
6376 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6377
6378 /* Don't delete PBO memory. */
6379 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6380 HeapFree(GetProcessHeap(), 0, mem);
6381
6382 return WINED3D_OK;
6383}
6384
6385static HRESULT surface_load_texture(struct wined3d_surface *surface,
6386 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6387{
6388 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6389 struct wined3d_device *device = surface->resource.device;
6390 enum wined3d_conversion_type convert;
6391 struct wined3d_context *context;
6392 UINT width, src_pitch, dst_pitch;
6393 struct wined3d_bo_address data;
6394 struct wined3d_format format;
6395 POINT dst_point = {0, 0};
6396 BYTE *mem;
6397
6398 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6399 && surface_is_offscreen(surface)
6400 && (surface->flags & SFLAG_INDRAWABLE))
6401 {
6402 surface_load_fb_texture(surface, srgb);
6403
6404 return WINED3D_OK;
6405 }
6406
6407 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6408 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6409 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6410 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6411 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6412 {
6413 if (srgb)
6414 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6415 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6416 else
6417 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6418 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6419
6420 return WINED3D_OK;
6421 }
6422
6423 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6424 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6425 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6426 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6427 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6428 {
6429 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6430 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6431 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6432
6433 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6434 &rect, surface, dst_location, &rect);
6435
6436 return WINED3D_OK;
6437 }
6438
6439 /* Upload from system memory */
6440
6441 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6442 TRUE /* We will use textures */, &format, &convert);
6443
6444 if (srgb)
6445 {
6446 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6447 {
6448 /* Performance warning... */
6449 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6450 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6451 }
6452 }
6453 else
6454 {
6455 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6456 {
6457 /* Performance warning... */
6458 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6459 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6460 }
6461 }
6462
6463 if (!(surface->flags & SFLAG_INSYSMEM))
6464 {
6465 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6466 /* Lets hope we get it from somewhere... */
6467 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6468 }
6469
6470 /* TODO: Use already acquired context when possible. */
6471 context = context_acquire(device, NULL);
6472
6473 surface_prepare_texture(surface, context, srgb);
6474 surface_bind_and_dirtify(surface, context, srgb);
6475
6476 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6477 {
6478 surface->flags |= SFLAG_GLCKEY;
6479 surface->gl_color_key = surface->src_blt_color_key;
6480 }
6481 else surface->flags &= ~SFLAG_GLCKEY;
6482
6483 width = surface->resource.width;
6484 src_pitch = wined3d_surface_get_pitch(surface);
6485
6486 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6487 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6488 * called. */
6489 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6490 {
6491 TRACE("Removing the pbo attached to surface %p.\n", surface);
6492 surface_remove_pbo(surface, gl_info);
6493 }
6494
6495 if (format.convert)
6496 {
6497 /* This code is entered for texture formats which need a fixup. */
6498 UINT height = surface->resource.height;
6499
6500 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6501 dst_pitch = width * format.conv_byte_count;
6502 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6503
6504 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6505 {
6506 ERR("Out of memory (%u).\n", dst_pitch * height);
6507 context_release(context);
6508 return E_OUTOFMEMORY;
6509 }
6510 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6511 format.byte_count = format.conv_byte_count;
6512 src_pitch = dst_pitch;
6513 }
6514 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6515 {
6516 /* This code is only entered for color keying fixups */
6517 UINT height = surface->resource.height;
6518
6519 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6520 dst_pitch = width * format.conv_byte_count;
6521 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6522
6523 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6524 {
6525 ERR("Out of memory (%u).\n", dst_pitch * height);
6526 context_release(context);
6527 return E_OUTOFMEMORY;
6528 }
6529 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6530 width, height, dst_pitch, convert, surface);
6531 format.byte_count = format.conv_byte_count;
6532 src_pitch = dst_pitch;
6533 }
6534 else
6535 {
6536 mem = surface->resource.allocatedMemory;
6537 }
6538
6539 data.buffer_object = surface->pbo;
6540 data.addr = mem;
6541 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6542
6543 context_release(context);
6544
6545 /* Don't delete PBO memory. */
6546 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6547 HeapFree(GetProcessHeap(), 0, mem);
6548
6549 return WINED3D_OK;
6550}
6551
6552static void surface_multisample_resolve(struct wined3d_surface *surface)
6553{
6554 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6555
6556 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6557 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6558
6559 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6560 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6561}
6562
6563HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6564{
6565 struct wined3d_device *device = surface->resource.device;
6566 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6567 HRESULT hr;
6568
6569 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6570
6571 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6572 {
6573 if (location == SFLAG_INTEXTURE && surface->flags & SFLAG_INDRAWABLE)
6574 {
6575 struct wined3d_context *context = context_acquire(device, NULL);
6576 surface_load_ds_location(surface, context, location);
6577 context_release(context);
6578#ifndef VBOX_WITH_WDDM
6579 return WINED3D_OK;
6580#else
6581 goto post_process;
6582#endif
6583 }
6584 else if (location & surface->flags && surface->draw_binding != SFLAG_INDRAWABLE)
6585 {
6586 /* Already up to date, nothing to do. */
6587#ifndef VBOX_WITH_WDDM
6588 return WINED3D_OK;
6589#else
6590 goto post_process;
6591#endif
6592 }
6593 else
6594 {
6595 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
6596 debug_surflocation(surface->flags & SFLAG_LOCATIONS), debug_surflocation(location));
6597 return WINED3DERR_INVALIDCALL;
6598 }
6599 }
6600
6601 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6602 location = SFLAG_INTEXTURE;
6603
6604 if (surface->flags & location)
6605 {
6606 TRACE("Location already up to date.\n");
6607
6608 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6609 && surface_need_pbo(surface, gl_info))
6610 surface_load_pbo(surface, gl_info);
6611
6612#ifndef VBOX_WITH_WDDM
6613 return WINED3D_OK;
6614#else
6615 goto post_process;
6616#endif
6617 }
6618
6619 if (WARN_ON(d3d_surface))
6620 {
6621 DWORD required_access = resource_access_from_location(location);
6622 if ((surface->resource.access_flags & required_access) != required_access)
6623 WARN("Operation requires %#x access, but surface only has %#x.\n",
6624 required_access, surface->resource.access_flags);
6625 }
6626
6627 if (!(surface->flags & SFLAG_LOCATIONS))
6628 {
6629 ERR("Surface %p does not have any up to date location.\n", surface);
6630 surface->flags |= SFLAG_LOST;
6631 return WINED3DERR_DEVICELOST;
6632 }
6633
6634 switch (location)
6635 {
6636 case SFLAG_INSYSMEM:
6637 surface_load_sysmem(surface, gl_info, rect);
6638 break;
6639
6640 case SFLAG_INDRAWABLE:
6641 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6642 return hr;
6643 break;
6644
6645 case SFLAG_INRB_RESOLVED:
6646 surface_multisample_resolve(surface);
6647 break;
6648
6649 case SFLAG_INTEXTURE:
6650 case SFLAG_INSRGBTEX:
6651 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6652 return hr;
6653 break;
6654
6655 default:
6656 ERR("Don't know how to handle location %#x.\n", location);
6657 break;
6658 }
6659
6660#ifdef VBOX_WITH_WDDM
6661post_process:
6662
6663 if (VBOXSHRC_IS_SHARED_UNLOCKED(surface))
6664 {
6665 /* with the shared resource only texture can be considered valid
6666 * to make sure changes done to the resource in the other device context are visible
6667 * because the resource contents is shared via texture.
6668 * One can load and use other locations as needed,
6669 * but they should be reloaded each time on each usage */
6670 Assert(!!(surface->flags & SFLAG_INTEXTURE) || !!(location & SFLAG_INTEXTURE));
6671 surface->flags &= ~SFLAG_LOCATIONS;
6672 surface->flags |= SFLAG_INTEXTURE;
6673 /* @todo: SFLAG_INSRGBTEX ?? */
6674// if (in_fbo)
6675// {
6676// surface->flags |= SFLAG_INDRAWABLE;
6677// }
6678 }
6679 else if (surface->flags & SFLAG_CLIENTMEM)
6680 {
6681 Assert(!!(surface->flags & SFLAG_INSYSMEM));
6682 surface->flags &= ~SFLAG_LOCATIONS;
6683 surface->flags |= SFLAG_INSYSMEM;
6684 }
6685 else
6686#endif
6687 {
6688 if (!rect)
6689 {
6690 surface->flags |= location;
6691
6692 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6693 surface_evict_sysmem(surface);
6694 }
6695
6696 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6697 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6698 {
6699 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6700 }
6701 }
6702
6703 return WINED3D_OK;
6704}
6705
6706BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6707{
6708 struct wined3d_swapchain *swapchain;
6709
6710 /* Not on a swapchain - must be offscreen */
6711 if (!(swapchain = surface->swapchain))
6712 return TRUE;
6713
6714 /* The front buffer is always onscreen */
6715 if (surface == swapchain->front_buffer) return FALSE;
6716
6717 /* If the swapchain is rendered to an FBO, the backbuffer is
6718 * offscreen, otherwise onscreen */
6719 return swapchain->render_to_fbo;
6720}
6721
6722static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6723/* Context activation is done by the caller. */
6724static void ffp_blit_free(struct wined3d_device *device) { }
6725
6726/* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6727/* Context activation is done by the caller. */
6728static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6729{
6730 BYTE table[256][4];
6731 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6732 GLenum target;
6733
6734 if (surface->container)
6735 target = surface->container->target;
6736 else
6737 target = surface->texture_target;
6738
6739 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6740
6741 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6742 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6743}
6744
6745/* Context activation is done by the caller. */
6746static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6747{
6748 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6749 const struct wined3d_gl_info *gl_info = context->gl_info;
6750 GLenum target;
6751
6752 if (surface->container)
6753 target = surface->container->target;
6754 else
6755 target = surface->texture_target;
6756
6757 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6758 * else the surface is converted in software at upload time in LoadLocation.
6759 */
6760 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6761 && gl_info->supported[EXT_PALETTED_TEXTURE])
6762 ffp_blit_p8_upload_palette(surface, gl_info);
6763
6764 gl_info->gl_ops.gl.p_glEnable(target);
6765 checkGLcall("glEnable(target)");
6766 return WINED3D_OK;
6767}
6768
6769/* Context activation is done by the caller. */
6770static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6771{
6772 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6773 checkGLcall("glDisable(GL_TEXTURE_2D)");
6774 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6775 {
6776 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6777 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6778 }
6779 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6780 {
6781 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6782 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6783 }
6784}
6785
6786static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6787 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6788 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6789{
6790 enum complex_fixup src_fixup;
6791
6792 switch (blit_op)
6793 {
6794 case WINED3D_BLIT_OP_COLOR_BLIT:
6795 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6796 return FALSE;
6797
6798 src_fixup = get_complex_fixup(src_format->color_fixup);
6799 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6800 {
6801 TRACE("Checking support for fixup:\n");
6802 dump_color_fixup_desc(src_format->color_fixup);
6803 }
6804
6805 if (!is_identity_fixup(dst_format->color_fixup))
6806 {
6807 TRACE("Destination fixups are not supported\n");
6808 return FALSE;
6809 }
6810
6811 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6812 {
6813 TRACE("P8 fixup supported\n");
6814 return TRUE;
6815 }
6816
6817 /* We only support identity conversions. */
6818 if (is_identity_fixup(src_format->color_fixup))
6819 {
6820 TRACE("[OK]\n");
6821 return TRUE;
6822 }
6823
6824 TRACE("[FAILED]\n");
6825 return FALSE;
6826
6827 case WINED3D_BLIT_OP_COLOR_FILL:
6828 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6829 return FALSE;
6830
6831 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6832 {
6833 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6834 return FALSE;
6835 }
6836 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6837 {
6838 TRACE("Color fill not supported\n");
6839 return FALSE;
6840 }
6841
6842 /* FIXME: We should reject color fills on formats with fixups,
6843 * but this would break P8 color fills for example. */
6844
6845 return TRUE;
6846
6847 case WINED3D_BLIT_OP_DEPTH_FILL:
6848 return TRUE;
6849
6850 default:
6851 TRACE("Unsupported blit_op=%d\n", blit_op);
6852 return FALSE;
6853 }
6854}
6855
6856/* Do not call while under the GL lock. */
6857static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6858 const RECT *dst_rect, const struct wined3d_color *color)
6859{
6860 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6861 struct wined3d_fb_state fb = {&dst_surface, NULL};
6862
6863 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6864
6865 return WINED3D_OK;
6866}
6867
6868/* Do not call while under the GL lock. */
6869static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6870 struct wined3d_surface *surface, const RECT *rect, float depth)
6871{
6872 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6873 struct wined3d_fb_state fb = {NULL, surface};
6874
6875 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6876
6877 return WINED3D_OK;
6878}
6879
6880const struct blit_shader ffp_blit = {
6881 ffp_blit_alloc,
6882 ffp_blit_free,
6883 ffp_blit_set,
6884 ffp_blit_unset,
6885 ffp_blit_supported,
6886 ffp_blit_color_fill,
6887 ffp_blit_depth_fill,
6888};
6889
6890static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6891{
6892 return WINED3D_OK;
6893}
6894
6895/* Context activation is done by the caller. */
6896static void cpu_blit_free(struct wined3d_device *device)
6897{
6898}
6899
6900/* Context activation is done by the caller. */
6901static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6902{
6903 return WINED3D_OK;
6904}
6905
6906/* Context activation is done by the caller. */
6907static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6908{
6909}
6910
6911static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6912 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6913 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6914{
6915 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6916 {
6917 return TRUE;
6918 }
6919
6920 return FALSE;
6921}
6922
6923static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6924 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6925 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6926{
6927 UINT row_block_count;
6928 const BYTE *src_row;
6929 BYTE *dst_row;
6930 UINT x, y;
6931
6932 src_row = src_data;
6933 dst_row = dst_data;
6934
6935 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6936
6937 if (!flags)
6938 {
6939 for (y = 0; y < update_h; y += format->block_height)
6940 {
6941 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6942 src_row += src_pitch;
6943 dst_row += dst_pitch;
6944 }
6945
6946 return WINED3D_OK;
6947 }
6948
6949 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6950 {
6951 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6952
6953 switch (format->id)
6954 {
6955 case WINED3DFMT_DXT1:
6956 for (y = 0; y < update_h; y += format->block_height)
6957 {
6958 struct block
6959 {
6960 WORD color[2];
6961 BYTE control_row[4];
6962 };
6963
6964 const struct block *s = (const struct block *)src_row;
6965 struct block *d = (struct block *)dst_row;
6966
6967 for (x = 0; x < row_block_count; ++x)
6968 {
6969 d[x].color[0] = s[x].color[0];
6970 d[x].color[1] = s[x].color[1];
6971 d[x].control_row[0] = s[x].control_row[3];
6972 d[x].control_row[1] = s[x].control_row[2];
6973 d[x].control_row[2] = s[x].control_row[1];
6974 d[x].control_row[3] = s[x].control_row[0];
6975 }
6976 src_row -= src_pitch;
6977 dst_row += dst_pitch;
6978 }
6979 return WINED3D_OK;
6980
6981 case WINED3DFMT_DXT3:
6982 for (y = 0; y < update_h; y += format->block_height)
6983 {
6984 struct block
6985 {
6986 WORD alpha_row[4];
6987 WORD color[2];
6988 BYTE control_row[4];
6989 };
6990
6991 const struct block *s = (const struct block *)src_row;
6992 struct block *d = (struct block *)dst_row;
6993
6994 for (x = 0; x < row_block_count; ++x)
6995 {
6996 d[x].alpha_row[0] = s[x].alpha_row[3];
6997 d[x].alpha_row[1] = s[x].alpha_row[2];
6998 d[x].alpha_row[2] = s[x].alpha_row[1];
6999 d[x].alpha_row[3] = s[x].alpha_row[0];
7000 d[x].color[0] = s[x].color[0];
7001 d[x].color[1] = s[x].color[1];
7002 d[x].control_row[0] = s[x].control_row[3];
7003 d[x].control_row[1] = s[x].control_row[2];
7004 d[x].control_row[2] = s[x].control_row[1];
7005 d[x].control_row[3] = s[x].control_row[0];
7006 }
7007 src_row -= src_pitch;
7008 dst_row += dst_pitch;
7009 }
7010 return WINED3D_OK;
7011
7012 default:
7013 FIXME("Compressed flip not implemented for format %s.\n",
7014 debug_d3dformat(format->id));
7015 return E_NOTIMPL;
7016 }
7017 }
7018
7019 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
7020 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
7021
7022 return E_NOTIMPL;
7023}
7024
7025static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
7026 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
7027 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
7028{
7029 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
7030 const struct wined3d_format *src_format, *dst_format;
7031 struct wined3d_surface *orig_src = src_surface;
7032 struct wined3d_map_desc dst_map, src_map;
7033 const BYTE *sbase = NULL;
7034 HRESULT hr = WINED3D_OK;
7035 const BYTE *sbuf;
7036 BYTE *dbuf;
7037 int x, y;
7038
7039 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
7040 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
7041 flags, fx, debug_d3dtexturefiltertype(filter));
7042
7043 if (src_surface == dst_surface)
7044 {
7045 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
7046 src_map = dst_map;
7047 src_format = dst_surface->resource.format;
7048 dst_format = src_format;
7049 }
7050 else
7051 {
7052 dst_format = dst_surface->resource.format;
7053 if (src_surface)
7054 {
7055 if (dst_surface->resource.format->id != src_surface->resource.format->id)
7056 {
7057 src_surface = surface_convert_format(src_surface, dst_format->id);
7058 if (!src_surface)
7059 {
7060 /* The conv function writes a FIXME */
7061 WARN("Cannot convert source surface format to dest format.\n");
7062 goto release;
7063 }
7064 }
7065 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
7066 src_format = src_surface->resource.format;
7067 }
7068 else
7069 {
7070 src_format = dst_format;
7071 }
7072
7073 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
7074 }
7075
7076 bpp = dst_surface->resource.format->byte_count;
7077 srcheight = src_rect->bottom - src_rect->top;
7078 srcwidth = src_rect->right - src_rect->left;
7079 dstheight = dst_rect->bottom - dst_rect->top;
7080 dstwidth = dst_rect->right - dst_rect->left;
7081 width = (dst_rect->right - dst_rect->left) * bpp;
7082
7083 if (src_surface)
7084 sbase = (BYTE *)src_map.data
7085 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
7086 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
7087 if (src_surface != dst_surface)
7088 dbuf = dst_map.data;
7089 else
7090 dbuf = (BYTE *)dst_map.data
7091 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
7092 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
7093
7094 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
7095 {
7096 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
7097
7098 if (src_surface == dst_surface)
7099 {
7100 FIXME("Only plain blits supported on compressed surfaces.\n");
7101 hr = E_NOTIMPL;
7102 goto release;
7103 }
7104
7105 if (srcheight != dstheight || srcwidth != dstwidth)
7106 {
7107 WARN("Stretching not supported on compressed surfaces.\n");
7108 hr = WINED3DERR_INVALIDCALL;
7109 goto release;
7110 }
7111
7112 if (!surface_check_block_align(src_surface, src_rect))
7113 {
7114 WARN("Source rectangle not block-aligned.\n");
7115 hr = WINED3DERR_INVALIDCALL;
7116 goto release;
7117 }
7118
7119 if (!surface_check_block_align(dst_surface, dst_rect))
7120 {
7121 WARN("Destination rectangle not block-aligned.\n");
7122 hr = WINED3DERR_INVALIDCALL;
7123 goto release;
7124 }
7125
7126 hr = surface_cpu_blt_compressed(sbase, dbuf,
7127 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
7128 src_format, flags, fx);
7129 goto release;
7130 }
7131
7132 /* First, all the 'source-less' blits */
7133 if (flags & WINEDDBLT_COLORFILL)
7134 {
7135 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
7136 flags &= ~WINEDDBLT_COLORFILL;
7137 }
7138
7139 if (flags & WINEDDBLT_DEPTHFILL)
7140 {
7141 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
7142 }
7143 if (flags & WINEDDBLT_ROP)
7144 {
7145 /* Catch some degenerate cases here. */
7146 switch (fx->dwROP)
7147 {
7148 case BLACKNESS:
7149 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
7150 break;
7151 case 0xaa0029: /* No-op */
7152 break;
7153 case WHITENESS:
7154 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
7155 break;
7156 case SRCCOPY: /* Well, we do that below? */
7157 break;
7158 default:
7159 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
7160 goto error;
7161 }
7162 flags &= ~WINEDDBLT_ROP;
7163 }
7164 if (flags & WINEDDBLT_DDROPS)
7165 {
7166 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
7167 }
7168 /* Now the 'with source' blits. */
7169 if (src_surface)
7170 {
7171 int sx, xinc, sy, yinc;
7172
7173 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
7174 goto release;
7175
7176 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
7177 && (srcwidth != dstwidth || srcheight != dstheight))
7178 {
7179 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
7180 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
7181 }
7182
7183 xinc = (srcwidth << 16) / dstwidth;
7184 yinc = (srcheight << 16) / dstheight;
7185
7186 if (!flags)
7187 {
7188 /* No effects, we can cheat here. */
7189 if (dstwidth == srcwidth)
7190 {
7191 if (dstheight == srcheight)
7192 {
7193 /* No stretching in either direction. This needs to be as
7194 * fast as possible. */
7195 sbuf = sbase;
7196
7197 /* Check for overlapping surfaces. */
7198 if (src_surface != dst_surface || dst_rect->top < src_rect->top
7199 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
7200 {
7201 /* No overlap, or dst above src, so copy from top downwards. */
7202 for (y = 0; y < dstheight; ++y)
7203 {
7204 memcpy(dbuf, sbuf, width);
7205 sbuf += src_map.row_pitch;
7206 dbuf += dst_map.row_pitch;
7207 }
7208 }
7209 else if (dst_rect->top > src_rect->top)
7210 {
7211 /* Copy from bottom upwards. */
7212 sbuf += src_map.row_pitch * dstheight;
7213 dbuf += dst_map.row_pitch * dstheight;
7214 for (y = 0; y < dstheight; ++y)
7215 {
7216 sbuf -= src_map.row_pitch;
7217 dbuf -= dst_map.row_pitch;
7218 memcpy(dbuf, sbuf, width);
7219 }
7220 }
7221 else
7222 {
7223 /* Src and dst overlapping on the same line, use memmove. */
7224 for (y = 0; y < dstheight; ++y)
7225 {
7226 memmove(dbuf, sbuf, width);
7227 sbuf += src_map.row_pitch;
7228 dbuf += dst_map.row_pitch;
7229 }
7230 }
7231 }
7232 else
7233 {
7234 /* Stretching in y direction only. */
7235 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7236 {
7237 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7238 memcpy(dbuf, sbuf, width);
7239 dbuf += dst_map.row_pitch;
7240 }
7241 }
7242 }
7243 else
7244 {
7245 /* Stretching in X direction. */
7246 int last_sy = -1;
7247 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7248 {
7249 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7250
7251 if ((sy >> 16) == (last_sy >> 16))
7252 {
7253 /* This source row is the same as last source row -
7254 * Copy the already stretched row. */
7255 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
7256 }
7257 else
7258 {
7259#define STRETCH_ROW(type) \
7260do { \
7261 const type *s = (const type *)sbuf; \
7262 type *d = (type *)dbuf; \
7263 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7264 d[x] = s[sx >> 16]; \
7265} while(0)
7266
7267 switch(bpp)
7268 {
7269 case 1:
7270 STRETCH_ROW(BYTE);
7271 break;
7272 case 2:
7273 STRETCH_ROW(WORD);
7274 break;
7275 case 4:
7276 STRETCH_ROW(DWORD);
7277 break;
7278 case 3:
7279 {
7280 const BYTE *s;
7281 BYTE *d = dbuf;
7282 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
7283 {
7284 DWORD pixel;
7285
7286 s = sbuf + 3 * (sx >> 16);
7287 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7288 d[0] = (pixel ) & 0xff;
7289 d[1] = (pixel >> 8) & 0xff;
7290 d[2] = (pixel >> 16) & 0xff;
7291 d += 3;
7292 }
7293 break;
7294 }
7295 default:
7296 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
7297 hr = WINED3DERR_NOTAVAILABLE;
7298 goto error;
7299 }
7300#undef STRETCH_ROW
7301 }
7302 dbuf += dst_map.row_pitch;
7303 last_sy = sy;
7304 }
7305 }
7306 }
7307 else
7308 {
7309 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
7310 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
7311 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
7312 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
7313 {
7314 /* The color keying flags are checked for correctness in ddraw */
7315 if (flags & WINEDDBLT_KEYSRC)
7316 {
7317 keylow = src_surface->src_blt_color_key.color_space_low_value;
7318 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
7319 }
7320 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
7321 {
7322 keylow = fx->ddckSrcColorkey.color_space_low_value;
7323 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
7324 }
7325
7326 if (flags & WINEDDBLT_KEYDEST)
7327 {
7328 /* Destination color keys are taken from the source surface! */
7329 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
7330 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
7331 }
7332 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
7333 {
7334 destkeylow = fx->ddckDestColorkey.color_space_low_value;
7335 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
7336 }
7337
7338 if (bpp == 1)
7339 {
7340 keymask = 0xff;
7341 }
7342 else
7343 {
7344 DWORD masks[3];
7345 get_color_masks(src_format, masks);
7346 keymask = masks[0]
7347 | masks[1]
7348 | masks[2];
7349 }
7350 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
7351 }
7352
7353 if (flags & WINEDDBLT_DDFX)
7354 {
7355 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
7356 LONG tmpxy;
7357 dTopLeft = dbuf;
7358 dTopRight = dbuf + ((dstwidth - 1) * bpp);
7359 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
7360 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
7361
7362 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
7363 {
7364 /* I don't think we need to do anything about this flag */
7365 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
7366 }
7367 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7368 {
7369 tmp = dTopRight;
7370 dTopRight = dTopLeft;
7371 dTopLeft = tmp;
7372 tmp = dBottomRight;
7373 dBottomRight = dBottomLeft;
7374 dBottomLeft = tmp;
7375 dstxinc = dstxinc * -1;
7376 }
7377 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7378 {
7379 tmp = dTopLeft;
7380 dTopLeft = dBottomLeft;
7381 dBottomLeft = tmp;
7382 tmp = dTopRight;
7383 dTopRight = dBottomRight;
7384 dBottomRight = tmp;
7385 dstyinc = dstyinc * -1;
7386 }
7387 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7388 {
7389 /* I don't think we need to do anything about this flag */
7390 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7391 }
7392 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7393 {
7394 tmp = dBottomRight;
7395 dBottomRight = dTopLeft;
7396 dTopLeft = tmp;
7397 tmp = dBottomLeft;
7398 dBottomLeft = dTopRight;
7399 dTopRight = tmp;
7400 dstxinc = dstxinc * -1;
7401 dstyinc = dstyinc * -1;
7402 }
7403 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7404 {
7405 tmp = dTopLeft;
7406 dTopLeft = dBottomLeft;
7407 dBottomLeft = dBottomRight;
7408 dBottomRight = dTopRight;
7409 dTopRight = tmp;
7410 tmpxy = dstxinc;
7411 dstxinc = dstyinc;
7412 dstyinc = tmpxy;
7413 dstxinc = dstxinc * -1;
7414 }
7415 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7416 {
7417 tmp = dTopLeft;
7418 dTopLeft = dTopRight;
7419 dTopRight = dBottomRight;
7420 dBottomRight = dBottomLeft;
7421 dBottomLeft = tmp;
7422 tmpxy = dstxinc;
7423 dstxinc = dstyinc;
7424 dstyinc = tmpxy;
7425 dstyinc = dstyinc * -1;
7426 }
7427 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7428 {
7429 /* I don't think we need to do anything about this flag */
7430 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7431 }
7432 dbuf = dTopLeft;
7433 flags &= ~(WINEDDBLT_DDFX);
7434 }
7435
7436#define COPY_COLORKEY_FX(type) \
7437do { \
7438 const type *s; \
7439 type *d = (type *)dbuf, *dx, tmp; \
7440 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7441 { \
7442 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7443 dx = d; \
7444 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7445 { \
7446 tmp = s[sx >> 16]; \
7447 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7448 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7449 { \
7450 dx[0] = tmp; \
7451 } \
7452 dx = (type *)(((BYTE *)dx) + dstxinc); \
7453 } \
7454 d = (type *)(((BYTE *)d) + dstyinc); \
7455 } \
7456} while(0)
7457
7458 switch (bpp)
7459 {
7460 case 1:
7461 COPY_COLORKEY_FX(BYTE);
7462 break;
7463 case 2:
7464 COPY_COLORKEY_FX(WORD);
7465 break;
7466 case 4:
7467 COPY_COLORKEY_FX(DWORD);
7468 break;
7469 case 3:
7470 {
7471 const BYTE *s;
7472 BYTE *d = dbuf, *dx;
7473 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7474 {
7475 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7476 dx = d;
7477 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7478 {
7479 DWORD pixel, dpixel = 0;
7480 s = sbuf + 3 * (sx>>16);
7481 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7482 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7483 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7484 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7485 {
7486 dx[0] = (pixel ) & 0xff;
7487 dx[1] = (pixel >> 8) & 0xff;
7488 dx[2] = (pixel >> 16) & 0xff;
7489 }
7490 dx += dstxinc;
7491 }
7492 d += dstyinc;
7493 }
7494 break;
7495 }
7496 default:
7497 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7498 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7499 hr = WINED3DERR_NOTAVAILABLE;
7500 goto error;
7501#undef COPY_COLORKEY_FX
7502 }
7503 }
7504 }
7505
7506error:
7507 if (flags && FIXME_ON(d3d_surface))
7508 {
7509 FIXME("\tUnsupported flags: %#x.\n", flags);
7510 }
7511
7512release:
7513 wined3d_surface_unmap(dst_surface);
7514 if (src_surface && src_surface != dst_surface)
7515 wined3d_surface_unmap(src_surface);
7516 /* Release the converted surface, if any. */
7517 if (src_surface && src_surface != orig_src)
7518 wined3d_surface_decref(src_surface);
7519
7520 return hr;
7521}
7522
7523/* Do not call while under the GL lock. */
7524static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7525 const RECT *dst_rect, const struct wined3d_color *color)
7526{
7527 static const RECT src_rect;
7528 WINEDDBLTFX BltFx;
7529
7530 memset(&BltFx, 0, sizeof(BltFx));
7531 BltFx.dwSize = sizeof(BltFx);
7532 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7533 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7534 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7535}
7536
7537/* Do not call while under the GL lock. */
7538static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7539 struct wined3d_surface *surface, const RECT *rect, float depth)
7540{
7541 FIXME("Depth filling not implemented by cpu_blit.\n");
7542 return WINED3DERR_INVALIDCALL;
7543}
7544
7545const struct blit_shader cpu_blit = {
7546 cpu_blit_alloc,
7547 cpu_blit_free,
7548 cpu_blit_set,
7549 cpu_blit_unset,
7550 cpu_blit_supported,
7551 cpu_blit_color_fill,
7552 cpu_blit_depth_fill,
7553};
7554
7555static HRESULT surface_init(struct wined3d_surface *surface, UINT alignment, UINT width, UINT height,
7556 enum wined3d_multisample_type multisample_type, UINT multisample_quality,
7557 struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7558 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops
7559#ifdef VBOX_WITH_WDDM
7560 , HANDLE *shared_handle
7561 , void *pvClientMem
7562#endif
7563 )
7564{
7565 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7566 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7567 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7568 unsigned int resource_size;
7569 HRESULT hr;
7570
7571 if (multisample_quality > 0)
7572 {
7573 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7574 multisample_quality = 0;
7575 }
7576
7577 /* Quick lockable sanity check.
7578 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7579 * this function is too deep to need to care about things like this.
7580 * Levels need to be checked too, since they all affect what can be done. */
7581 switch (pool)
7582 {
7583 case WINED3D_POOL_SCRATCH:
7584 if (!lockable)
7585 {
7586 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7587 "which are mutually exclusive, setting lockable to TRUE.\n");
7588 lockable = TRUE;
7589 }
7590 break;
7591
7592 case WINED3D_POOL_SYSTEM_MEM:
7593 if (!lockable)
7594 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7595 break;
7596
7597 case WINED3D_POOL_MANAGED:
7598 if (usage & WINED3DUSAGE_DYNAMIC)
7599 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7600 break;
7601
7602 case WINED3D_POOL_DEFAULT:
7603 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7604 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7605 break;
7606
7607 default:
7608 FIXME("Unknown pool %#x.\n", pool);
7609 break;
7610 };
7611
7612 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7613 FIXME("Trying to create a render target that isn't in the default pool.\n");
7614
7615 /* FIXME: Check that the format is supported by the device. */
7616
7617 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7618 if (!resource_size)
7619 return WINED3DERR_INVALIDCALL;
7620
7621 if (device->wined3d->flags & WINED3D_NO3D)
7622 surface->surface_ops = &gdi_surface_ops;
7623 else
7624 surface->surface_ops = &surface_ops;
7625
7626 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7627 multisample_type, multisample_quality, usage, pool, width, height, 1,
7628 resource_size, parent, parent_ops, &surface_resource_ops
7629#ifdef VBOX_WITH_WDDM
7630 , shared_handle
7631 , pvClientMem
7632#endif
7633 );
7634 if (FAILED(hr))
7635 {
7636 WARN("Failed to initialize resource, returning %#x.\n", hr);
7637 return hr;
7638 }
7639
7640#ifdef VBOX_WITH_WDDM
7641 /* this will be a nop for the non-shared resource,
7642 * for the shared resource this will ensure the surface is initialized properly */
7643 surface_shrc_lock(surface);
7644#endif
7645
7646 /* "Standalone" surface. */
7647 surface_set_container(surface, NULL);
7648
7649 list_init(&surface->overlays);
7650
7651 /* Flags */
7652 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7653 if (flags & WINED3D_SURFACE_DISCARD)
7654 surface->flags |= SFLAG_DISCARD;
7655 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7656 surface->flags |= SFLAG_PIN_SYSMEM;
7657 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7658 surface->flags |= SFLAG_LOCKABLE;
7659 /* I'm not sure if this qualifies as a hack or as an optimization. It
7660 * seems reasonable to assume that lockable render targets will get
7661 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7662 * creation. However, the other reason we want to do this is that several
7663 * ddraw applications access surface memory while the surface isn't
7664 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7665 * future locks prevents these from crashing. */
7666 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7667 surface->flags |= SFLAG_DYNLOCK;
7668#ifdef VBOX_WITH_WDDM
7669 if (pool == WINED3D_POOL_SYSTEM_MEM && pvClientMem) surface->flags |= SFLAG_CLIENTMEM;
7670#endif
7671
7672 /* Mark the texture as dirty so that it gets loaded first time around. */
7673 surface_add_dirty_rect(surface, NULL);
7674 list_init(&surface->renderbuffers);
7675
7676 TRACE("surface %p, memory %p, size %u\n",
7677 surface, surface->resource.allocatedMemory, surface->resource.size);
7678
7679 /* Call the private setup routine */
7680 hr = surface->surface_ops->surface_private_setup(surface);
7681 if (FAILED(hr))
7682 {
7683 ERR("Private setup failed, returning %#x\n", hr);
7684 surface_cleanup(surface);
7685 return hr;
7686 }
7687
7688 /* Similar to lockable rendertargets above, creating the DIB section
7689 * during surface initialization prevents the sysmem pointer from changing
7690 * after a wined3d_surface_getdc() call. */
7691 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7692 && SUCCEEDED(surface_create_dib_section(surface)))
7693 {
7694 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7695 surface->resource.heapMemory = NULL;
7696 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7697 }
7698
7699#ifdef VBOX_WITH_WDDM
7700 if (VBOXSHRC_IS_SHARED(surface))
7701 {
7702 Assert(shared_handle);
7703 if (!VBOXSHRC_IS_SHARED_OPENED(surface))
7704 {
7705 surface_shrc_unlock(surface);
7706 Assert(!(*shared_handle));
7707 *shared_handle = VBOXSHRC_GET_SHAREHANDLE(surface);
7708 }
7709 else
7710 {
7711 VBOXSHRC_UNLOCK(surface);
7712 Assert(!VBOXSHRC_IS_LOCKED(surface));
7713#ifdef DEBUG_misha
7714 ERR("test this!");
7715#endif
7716 surface_setup_location_onopen(surface);
7717 Assert(*shared_handle);
7718 Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(surface));
7719 }
7720
7721 Assert(!device->isInDraw);
7722
7723 /* flush to ensure the texture is allocated/referenced before it is used/released by another
7724 * process opening/creating it */
7725 /* flush to ensure the texture is allocated/referenced before it is used/released by another
7726 * process opening/creating it */
7727 Assert(device->context_count == 1);
7728 pVBoxFlushToHost(device->contexts[0]->glCtx);
7729 }
7730 else
7731 {
7732 Assert(!shared_handle);
7733 }
7734#endif
7735
7736 return hr;
7737}
7738
7739HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7740 enum wined3d_format_id format_id, DWORD usage, enum wined3d_pool pool,
7741 enum wined3d_multisample_type multisample_type, DWORD multisample_quality, DWORD flags,
7742 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface
7743#ifdef VBOX_WITH_WDDM
7744 , HANDLE *shared_handle
7745 , void *pvClientMem
7746#endif
7747 )
7748{
7749 struct wined3d_surface *object;
7750 HRESULT hr;
7751
7752 TRACE("device %p, width %u, height %u, format %s\n",
7753 device, width, height, debug_d3dformat(format_id));
7754 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7755 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7756 TRACE("flags %#x, parent %p, parent_ops %p.\n", flags, parent, parent_ops);
7757
7758 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7759 if (!object)
7760 return WINED3DERR_OUTOFVIDEOMEMORY;
7761
7762#ifdef VBOX_WITH_WDDM
7763 if (FAILED(hr = surface_init(object, device->surface_alignment, width, height, multisample_type,
7764 multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops
7765 , shared_handle
7766 , pvClientMem
7767 )))
7768#else
7769 if (FAILED(hr = surface_init(object, device->surface_alignment, width, height, multisample_type,
7770 multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops)))
7771#endif
7772 {
7773 WARN("Failed to initialize surface, returning %#x.\n", hr);
7774 HeapFree(GetProcessHeap(), 0, object);
7775 return hr;
7776 }
7777
7778 TRACE("Created surface %p.\n", object);
7779 *surface = object;
7780
7781 return hr;
7782}
7783
7784#ifdef VBOX_WITH_WDDM
7785HRESULT CDECL wined3d_surface_get_host_id(struct wined3d_surface *surface, uint32_t *id)
7786{
7787 struct wined3d_texture *texture;
7788 surface_internal_preload(surface, SRGB_RGB);
7789
7790 texture = surface->container;
7791 if (texture && texture->level_count != 1 && texture->layer_count != 1)
7792 {
7793 ERR("unsupported level(%d) or layer(%d) count", texture->level_count, texture->layer_count);
7794 }
7795
7796 if (!surface->texture_name)
7797 {
7798 ERR("no texture name!");
7799 return E_FAIL;
7800 }
7801
7802 *id = surface->texture_name;
7803 return S_OK;
7804}
7805
7806HRESULT CDECL wined3d_surface_sync_to_host(struct wined3d_surface *surface)
7807{
7808 HRESULT hr = surface_load_location(surface, SFLAG_INTEXTURE, NULL);
7809 if (!SUCCEEDED(hr))
7810 {
7811 ERR("surface_load_location failed hr 0x%x", hr);
7812 return hr;
7813 }
7814
7815 return S_OK;
7816}
7817#endif
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