VirtualBox

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

最後變更 在這個檔案從48611是 48611,由 vboxsync 提交於 12 年 前

wined3d: fix win8.1 ie rendering (unpack alignment fix)

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

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