ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

surface.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 1997-2000 Marcus Meissner
00003  * Copyright 1998-2000 Lionel Ulmer
00004  * Copyright 2000-2001 TransGaming Technologies Inc.
00005  * Copyright 2002-2005 Jason Edmeades
00006  * Copyright 2002-2003 Raphael Junqueira
00007  * Copyright 2004 Christian Costa
00008  * Copyright 2005 Oliver Stieber
00009  * Copyright 2006-2011 Stefan Dösinger for CodeWeavers
00010  * Copyright 2007-2008 Henri Verbeet
00011  * Copyright 2006-2008 Roderick Colenbrander
00012  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
00013  *
00014  * This library is free software; you can redistribute it and/or
00015  * modify it under the terms of the GNU Lesser General Public
00016  * License as published by the Free Software Foundation; either
00017  * version 2.1 of the License, or (at your option) any later version.
00018  *
00019  * This library is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00022  * Lesser General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public
00025  * License along with this library; if not, write to the Free Software
00026  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00027  */
00028 
00029 #include "config.h"
00030 #include "wine/port.h"
00031 #include "wined3d_private.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
00034 WINE_DECLARE_DEBUG_CHANNEL(d3d);
00035 
00036 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
00037         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
00038         const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter);
00039 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
00040         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
00041         enum wined3d_texture_filter_type filter);
00042 
00043 static void surface_cleanup(struct wined3d_surface *surface)
00044 {
00045     struct wined3d_surface *overlay, *cur;
00046 
00047     TRACE("surface %p.\n", surface);
00048 
00049     if (surface->texture_name || (surface->flags & SFLAG_PBO)
00050              || surface->rb_multisample || surface->rb_resolved
00051              || !list_empty(&surface->renderbuffers))
00052     {
00053         struct wined3d_renderbuffer_entry *entry, *entry2;
00054         const struct wined3d_gl_info *gl_info;
00055         struct wined3d_context *context;
00056 
00057         context = context_acquire(surface->resource.device, NULL);
00058         gl_info = context->gl_info;
00059 
00060         ENTER_GL();
00061 
00062         if (surface->texture_name)
00063         {
00064             TRACE("Deleting texture %u.\n", surface->texture_name);
00065             glDeleteTextures(1, &surface->texture_name);
00066         }
00067 
00068         if (surface->flags & SFLAG_PBO)
00069         {
00070             TRACE("Deleting PBO %u.\n", surface->pbo);
00071             GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
00072         }
00073 
00074         if (surface->rb_multisample)
00075         {
00076             TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
00077             gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
00078         }
00079 
00080         if (surface->rb_resolved)
00081         {
00082             TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
00083             gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
00084         }
00085 
00086         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
00087         {
00088             TRACE("Deleting renderbuffer %u.\n", entry->id);
00089             gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
00090             HeapFree(GetProcessHeap(), 0, entry);
00091         }
00092 
00093         LEAVE_GL();
00094 
00095         context_release(context);
00096     }
00097 
00098     if (surface->flags & SFLAG_DIBSECTION)
00099     {
00100         DeleteDC(surface->hDC);
00101         DeleteObject(surface->dib.DIBsection);
00102         surface->dib.bitmap_data = NULL;
00103         surface->resource.allocatedMemory = NULL;
00104     }
00105 
00106     if (surface->flags & SFLAG_USERPTR)
00107         wined3d_surface_set_mem(surface, NULL);
00108     if (surface->overlay_dest)
00109         list_remove(&surface->overlay_entry);
00110 
00111     LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
00112     {
00113         list_remove(&overlay->overlay_entry);
00114         overlay->overlay_dest = NULL;
00115     }
00116 
00117     resource_cleanup(&surface->resource);
00118 }
00119 
00120 void surface_update_draw_binding(struct wined3d_surface *surface)
00121 {
00122     if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
00123         surface->draw_binding = SFLAG_INDRAWABLE;
00124     else if (surface->resource.multisample_type)
00125         surface->draw_binding = SFLAG_INRB_MULTISAMPLE;
00126     else
00127         surface->draw_binding = SFLAG_INTEXTURE;
00128 }
00129 
00130 void surface_set_container(struct wined3d_surface *surface, enum wined3d_container_type type, void *container)
00131 {
00132     TRACE("surface %p, container %p.\n", surface, container);
00133 
00134     if (!container && type != WINED3D_CONTAINER_NONE)
00135         ERR("Setting NULL container of type %#x.\n", type);
00136 
00137     if (type == WINED3D_CONTAINER_SWAPCHAIN)
00138     {
00139         surface->get_drawable_size = get_drawable_size_swapchain;
00140     }
00141     else
00142     {
00143         switch (wined3d_settings.offscreen_rendering_mode)
00144         {
00145             case ORM_FBO:
00146                 surface->get_drawable_size = get_drawable_size_fbo;
00147                 break;
00148 
00149             case ORM_BACKBUFFER:
00150                 surface->get_drawable_size = get_drawable_size_backbuffer;
00151                 break;
00152 
00153             default:
00154                 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
00155                 return;
00156         }
00157     }
00158 
00159     surface->container.type = type;
00160     surface->container.u.base = container;
00161     surface_update_draw_binding(surface);
00162 }
00163 
00164 struct blt_info
00165 {
00166     GLenum binding;
00167     GLenum bind_target;
00168     enum tex_types tex_type;
00169     GLfloat coords[4][3];
00170 };
00171 
00172 struct float_rect
00173 {
00174     float l;
00175     float t;
00176     float r;
00177     float b;
00178 };
00179 
00180 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
00181 {
00182     f->l = ((r->left * 2.0f) / w) - 1.0f;
00183     f->t = ((r->top * 2.0f) / h) - 1.0f;
00184     f->r = ((r->right * 2.0f) / w) - 1.0f;
00185     f->b = ((r->bottom * 2.0f) / h) - 1.0f;
00186 }
00187 
00188 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
00189 {
00190     GLfloat (*coords)[3] = info->coords;
00191     struct float_rect f;
00192 
00193     switch (target)
00194     {
00195         default:
00196             FIXME("Unsupported texture target %#x\n", target);
00197             /* Fall back to GL_TEXTURE_2D */
00198         case GL_TEXTURE_2D:
00199             info->binding = GL_TEXTURE_BINDING_2D;
00200             info->bind_target = GL_TEXTURE_2D;
00201             info->tex_type = tex_2d;
00202             coords[0][0] = (float)rect->left / w;
00203             coords[0][1] = (float)rect->top / h;
00204             coords[0][2] = 0.0f;
00205 
00206             coords[1][0] = (float)rect->right / w;
00207             coords[1][1] = (float)rect->top / h;
00208             coords[1][2] = 0.0f;
00209 
00210             coords[2][0] = (float)rect->left / w;
00211             coords[2][1] = (float)rect->bottom / h;
00212             coords[2][2] = 0.0f;
00213 
00214             coords[3][0] = (float)rect->right / w;
00215             coords[3][1] = (float)rect->bottom / h;
00216             coords[3][2] = 0.0f;
00217             break;
00218 
00219         case GL_TEXTURE_RECTANGLE_ARB:
00220             info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
00221             info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
00222             info->tex_type = tex_rect;
00223             coords[0][0] = rect->left;  coords[0][1] = rect->top;       coords[0][2] = 0.0f;
00224             coords[1][0] = rect->right; coords[1][1] = rect->top;       coords[1][2] = 0.0f;
00225             coords[2][0] = rect->left;  coords[2][1] = rect->bottom;    coords[2][2] = 0.0f;
00226             coords[3][0] = rect->right; coords[3][1] = rect->bottom;    coords[3][2] = 0.0f;
00227             break;
00228 
00229         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
00230             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
00231             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
00232             info->tex_type = tex_cube;
00233             cube_coords_float(rect, w, h, &f);
00234 
00235             coords[0][0] =  1.0f;   coords[0][1] = -f.t;   coords[0][2] = -f.l;
00236             coords[1][0] =  1.0f;   coords[1][1] = -f.t;   coords[1][2] = -f.r;
00237             coords[2][0] =  1.0f;   coords[2][1] = -f.b;   coords[2][2] = -f.l;
00238             coords[3][0] =  1.0f;   coords[3][1] = -f.b;   coords[3][2] = -f.r;
00239             break;
00240 
00241         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
00242             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
00243             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
00244             info->tex_type = tex_cube;
00245             cube_coords_float(rect, w, h, &f);
00246 
00247             coords[0][0] = -1.0f;   coords[0][1] = -f.t;   coords[0][2] = f.l;
00248             coords[1][0] = -1.0f;   coords[1][1] = -f.t;   coords[1][2] = f.r;
00249             coords[2][0] = -1.0f;   coords[2][1] = -f.b;   coords[2][2] = f.l;
00250             coords[3][0] = -1.0f;   coords[3][1] = -f.b;   coords[3][2] = f.r;
00251             break;
00252 
00253         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
00254             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
00255             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
00256             info->tex_type = tex_cube;
00257             cube_coords_float(rect, w, h, &f);
00258 
00259             coords[0][0] = f.l;   coords[0][1] =  1.0f;   coords[0][2] = f.t;
00260             coords[1][0] = f.r;   coords[1][1] =  1.0f;   coords[1][2] = f.t;
00261             coords[2][0] = f.l;   coords[2][1] =  1.0f;   coords[2][2] = f.b;
00262             coords[3][0] = f.r;   coords[3][1] =  1.0f;   coords[3][2] = f.b;
00263             break;
00264 
00265         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
00266             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
00267             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
00268             info->tex_type = tex_cube;
00269             cube_coords_float(rect, w, h, &f);
00270 
00271             coords[0][0] = f.l;   coords[0][1] = -1.0f;   coords[0][2] = -f.t;
00272             coords[1][0] = f.r;   coords[1][1] = -1.0f;   coords[1][2] = -f.t;
00273             coords[2][0] = f.l;   coords[2][1] = -1.0f;   coords[2][2] = -f.b;
00274             coords[3][0] = f.r;   coords[3][1] = -1.0f;   coords[3][2] = -f.b;
00275             break;
00276 
00277         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
00278             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
00279             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
00280             info->tex_type = tex_cube;
00281             cube_coords_float(rect, w, h, &f);
00282 
00283             coords[0][0] = f.l;   coords[0][1] = -f.t;   coords[0][2] =  1.0f;
00284             coords[1][0] = f.r;   coords[1][1] = -f.t;   coords[1][2] =  1.0f;
00285             coords[2][0] = f.l;   coords[2][1] = -f.b;   coords[2][2] =  1.0f;
00286             coords[3][0] = f.r;   coords[3][1] = -f.b;   coords[3][2] =  1.0f;
00287             break;
00288 
00289         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
00290             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
00291             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
00292             info->tex_type = tex_cube;
00293             cube_coords_float(rect, w, h, &f);
00294 
00295             coords[0][0] = -f.l;   coords[0][1] = -f.t;   coords[0][2] = -1.0f;
00296             coords[1][0] = -f.r;   coords[1][1] = -f.t;   coords[1][2] = -1.0f;
00297             coords[2][0] = -f.l;   coords[2][1] = -f.b;   coords[2][2] = -1.0f;
00298             coords[3][0] = -f.r;   coords[3][1] = -f.b;   coords[3][2] = -1.0f;
00299             break;
00300     }
00301 }
00302 
00303 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
00304 {
00305     if (rect_in)
00306         *rect_out = *rect_in;
00307     else
00308     {
00309         rect_out->left = 0;
00310         rect_out->top = 0;
00311         rect_out->right = surface->resource.width;
00312         rect_out->bottom = surface->resource.height;
00313     }
00314 }
00315 
00316 /* GL locking and context activation is done by the caller */
00317 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
00318         const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
00319 {
00320     struct blt_info info;
00321 
00322     surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
00323 
00324     glEnable(info.bind_target);
00325     checkGLcall("glEnable(bind_target)");
00326 
00327     context_bind_texture(context, info.bind_target, src_surface->texture_name);
00328 
00329     /* Filtering for StretchRect */
00330     glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
00331             wined3d_gl_mag_filter(magLookup, filter));
00332     checkGLcall("glTexParameteri");
00333     glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
00334             wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
00335     checkGLcall("glTexParameteri");
00336     glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
00337     glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
00338     if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
00339         glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
00340     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00341     checkGLcall("glTexEnvi");
00342 
00343     /* Draw a quad */
00344     glBegin(GL_TRIANGLE_STRIP);
00345     glTexCoord3fv(info.coords[0]);
00346     glVertex2i(dst_rect->left, dst_rect->top);
00347 
00348     glTexCoord3fv(info.coords[1]);
00349     glVertex2i(dst_rect->right, dst_rect->top);
00350 
00351     glTexCoord3fv(info.coords[2]);
00352     glVertex2i(dst_rect->left, dst_rect->bottom);
00353 
00354     glTexCoord3fv(info.coords[3]);
00355     glVertex2i(dst_rect->right, dst_rect->bottom);
00356     glEnd();
00357 
00358     /* Unbind the texture */
00359     context_bind_texture(context, info.bind_target, 0);
00360 
00361     /* We changed the filtering settings on the texture. Inform the
00362      * container about this to get the filters reset properly next draw. */
00363     if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE)
00364     {
00365         struct wined3d_texture *texture = src_surface->container.u.texture;
00366         texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
00367         texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
00368         texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
00369         texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE;
00370     }
00371 }
00372 
00373 static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
00374 {
00375     const struct wined3d_format *format = surface->resource.format;
00376     SYSTEM_INFO sysInfo;
00377     BITMAPINFO *b_info;
00378     int extraline = 0;
00379     DWORD *masks;
00380     UINT usage;
00381     HDC dc;
00382 
00383     TRACE("surface %p.\n", surface);
00384 
00385     if (!(format->flags & WINED3DFMT_FLAG_GETDC))
00386     {
00387         WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
00388         return WINED3DERR_INVALIDCALL;
00389     }
00390 
00391     switch (format->byte_count)
00392     {
00393         case 2:
00394         case 4:
00395             /* Allocate extra space to store the RGB bit masks. */
00396             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
00397             break;
00398 
00399         case 3:
00400             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
00401             break;
00402 
00403         default:
00404             /* Allocate extra space for a palette. */
00405             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00406                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
00407             break;
00408     }
00409 
00410     if (!b_info)
00411         return E_OUTOFMEMORY;
00412 
00413     /* Some applications access the surface in via DWORDs, and do not take
00414      * the necessary care at the end of the surface. So we need at least
00415      * 4 extra bytes at the end of the surface. Check against the page size,
00416      * if the last page used for the surface has at least 4 spare bytes we're
00417      * safe, otherwise add an extra line to the DIB section. */
00418     GetSystemInfo(&sysInfo);
00419     if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
00420     {
00421         extraline = 1;
00422         TRACE("Adding an extra line to the DIB section.\n");
00423     }
00424 
00425     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00426     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
00427     b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
00428     b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
00429     b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
00430             * wined3d_surface_get_pitch(surface);
00431     b_info->bmiHeader.biPlanes = 1;
00432     b_info->bmiHeader.biBitCount = format->byte_count * 8;
00433 
00434     b_info->bmiHeader.biXPelsPerMeter = 0;
00435     b_info->bmiHeader.biYPelsPerMeter = 0;
00436     b_info->bmiHeader.biClrUsed = 0;
00437     b_info->bmiHeader.biClrImportant = 0;
00438 
00439     /* Get the bit masks */
00440     masks = (DWORD *)b_info->bmiColors;
00441     switch (surface->resource.format->id)
00442     {
00443         case WINED3DFMT_B8G8R8_UNORM:
00444             usage = DIB_RGB_COLORS;
00445             b_info->bmiHeader.biCompression = BI_RGB;
00446             break;
00447 
00448         case WINED3DFMT_B5G5R5X1_UNORM:
00449         case WINED3DFMT_B5G5R5A1_UNORM:
00450         case WINED3DFMT_B4G4R4A4_UNORM:
00451         case WINED3DFMT_B4G4R4X4_UNORM:
00452         case WINED3DFMT_B2G3R3_UNORM:
00453         case WINED3DFMT_B2G3R3A8_UNORM:
00454         case WINED3DFMT_R10G10B10A2_UNORM:
00455         case WINED3DFMT_R8G8B8A8_UNORM:
00456         case WINED3DFMT_R8G8B8X8_UNORM:
00457         case WINED3DFMT_B10G10R10A2_UNORM:
00458         case WINED3DFMT_B5G6R5_UNORM:
00459         case WINED3DFMT_R16G16B16A16_UNORM:
00460             usage = 0;
00461             b_info->bmiHeader.biCompression = BI_BITFIELDS;
00462             masks[0] = format->red_mask;
00463             masks[1] = format->green_mask;
00464             masks[2] = format->blue_mask;
00465             break;
00466 
00467         default:
00468             /* Don't know palette */
00469             b_info->bmiHeader.biCompression = BI_RGB;
00470             usage = 0;
00471             break;
00472     }
00473 
00474     if (!(dc = GetDC(0)))
00475     {
00476         HeapFree(GetProcessHeap(), 0, b_info);
00477         return HRESULT_FROM_WIN32(GetLastError());
00478     }
00479 
00480     TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
00481             b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
00482             b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
00483     surface->dib.DIBsection = CreateDIBSection(dc, b_info, usage, &surface->dib.bitmap_data, 0, 0);
00484     ReleaseDC(0, dc);
00485 
00486     if (!surface->dib.DIBsection)
00487     {
00488         ERR("Failed to create DIB section.\n");
00489         HeapFree(GetProcessHeap(), 0, b_info);
00490         return HRESULT_FROM_WIN32(GetLastError());
00491     }
00492 
00493     TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
00494     /* Copy the existing surface to the dib section. */
00495     if (surface->resource.allocatedMemory)
00496     {
00497         memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
00498                 surface->resource.height * wined3d_surface_get_pitch(surface));
00499     }
00500     else
00501     {
00502         /* This is to make maps read the GL texture although memory is allocated. */
00503         surface->flags &= ~SFLAG_INSYSMEM;
00504     }
00505     surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
00506 
00507     HeapFree(GetProcessHeap(), 0, b_info);
00508 
00509     /* Now allocate a DC. */
00510     surface->hDC = CreateCompatibleDC(0);
00511     SelectObject(surface->hDC, surface->dib.DIBsection);
00512     TRACE("Using wined3d palette %p.\n", surface->palette);
00513     SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
00514 
00515     surface->flags |= SFLAG_DIBSECTION;
00516 
00517     HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
00518     surface->resource.heapMemory = NULL;
00519 
00520     return WINED3D_OK;
00521 }
00522 
00523 static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
00524 {
00525     if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
00526         return FALSE;
00527     if (!(surface->flags & SFLAG_DYNLOCK))
00528         return FALSE;
00529     if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
00530         return FALSE;
00531     if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
00532         return FALSE;
00533 
00534     return TRUE;
00535 }
00536 
00537 static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
00538 {
00539     struct wined3d_context *context;
00540     GLenum error;
00541 
00542     context = context_acquire(surface->resource.device, NULL);
00543     ENTER_GL();
00544 
00545     GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
00546     error = glGetError();
00547     if (!surface->pbo || error != GL_NO_ERROR)
00548         ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
00549 
00550     TRACE("Binding PBO %u.\n", surface->pbo);
00551 
00552     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
00553     checkGLcall("glBindBufferARB");
00554 
00555     GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
00556             surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
00557     checkGLcall("glBufferDataARB");
00558 
00559     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
00560     checkGLcall("glBindBufferARB");
00561 
00562     /* We don't need the system memory anymore and we can't even use it for PBOs. */
00563     if (!(surface->flags & SFLAG_CLIENT))
00564     {
00565         HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
00566         surface->resource.heapMemory = NULL;
00567     }
00568     surface->resource.allocatedMemory = NULL;
00569     surface->flags |= SFLAG_PBO;
00570     LEAVE_GL();
00571     context_release(context);
00572 }
00573 
00574 static void surface_prepare_system_memory(struct wined3d_surface *surface)
00575 {
00576     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
00577 
00578     TRACE("surface %p.\n", surface);
00579 
00580     if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
00581         surface_load_pbo(surface, gl_info);
00582     else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
00583     {
00584         /* Whatever surface we have, make sure that there is memory allocated
00585          * for the downloaded copy, or a PBO to map. */
00586         if (!surface->resource.heapMemory)
00587             surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
00588 
00589         surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
00590                 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
00591 
00592         if (surface->flags & SFLAG_INSYSMEM)
00593             ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
00594     }
00595 }
00596 
00597 static void surface_evict_sysmem(struct wined3d_surface *surface)
00598 {
00599     if (surface->flags & SFLAG_DONOTFREE)
00600         return;
00601 
00602     HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
00603     surface->resource.allocatedMemory = NULL;
00604     surface->resource.heapMemory = NULL;
00605     surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
00606 }
00607 
00608 /* Context activation is done by the caller. */
00609 static void surface_bind_and_dirtify(struct wined3d_surface *surface,
00610         struct wined3d_context *context, BOOL srgb)
00611 {
00612     struct wined3d_device *device = surface->resource.device;
00613     DWORD active_sampler;
00614 
00615     /* We don't need a specific texture unit, but after binding the texture
00616      * the current unit is dirty. Read the unit back instead of switching to
00617      * 0, this avoids messing around with the state manager's GL states. The
00618      * current texture unit should always be a valid one.
00619      *
00620      * To be more specific, this is tricky because we can implicitly be
00621      * called from sampler() in state.c. This means we can't touch anything
00622      * other than whatever happens to be the currently active texture, or we
00623      * would risk marking already applied sampler states dirty again. */
00624     active_sampler = device->rev_tex_unit_map[context->active_texture];
00625 
00626     if (active_sampler != WINED3D_UNMAPPED_STAGE)
00627         device_invalidate_state(device, STATE_SAMPLER(active_sampler));
00628     surface_bind(surface, context, srgb);
00629 }
00630 
00631 static void surface_force_reload(struct wined3d_surface *surface)
00632 {
00633     surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
00634 }
00635 
00636 static void surface_release_client_storage(struct wined3d_surface *surface)
00637 {
00638     struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
00639 
00640     ENTER_GL();
00641     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
00642     if (surface->texture_name)
00643     {
00644         surface_bind_and_dirtify(surface, context, FALSE);
00645         glTexImage2D(surface->texture_target, surface->texture_level,
00646                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
00647     }
00648     if (surface->texture_name_srgb)
00649     {
00650         surface_bind_and_dirtify(surface, context, TRUE);
00651         glTexImage2D(surface->texture_target, surface->texture_level,
00652                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
00653     }
00654     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
00655     LEAVE_GL();
00656 
00657     context_release(context);
00658 
00659     surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
00660     surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
00661     surface_force_reload(surface);
00662 }
00663 
00664 static HRESULT surface_private_setup(struct wined3d_surface *surface)
00665 {
00666     /* TODO: Check against the maximum texture sizes supported by the video card. */
00667     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
00668     unsigned int pow2Width, pow2Height;
00669 
00670     TRACE("surface %p.\n", surface);
00671 
00672     surface->texture_name = 0;
00673     surface->texture_target = GL_TEXTURE_2D;
00674 
00675     /* Non-power2 support */
00676     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
00677     {
00678         pow2Width = surface->resource.width;
00679         pow2Height = surface->resource.height;
00680     }
00681     else
00682     {
00683         /* Find the nearest pow2 match */
00684         pow2Width = pow2Height = 1;
00685         while (pow2Width < surface->resource.width)
00686             pow2Width <<= 1;
00687         while (pow2Height < surface->resource.height)
00688             pow2Height <<= 1;
00689     }
00690     surface->pow2Width = pow2Width;
00691     surface->pow2Height = pow2Height;
00692 
00693     if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
00694     {
00695         /* TODO: Add support for non power two compressed textures. */
00696         if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
00697         {
00698             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
00699                   surface, surface->resource.width, surface->resource.height);
00700             return WINED3DERR_NOTAVAILABLE;
00701         }
00702     }
00703 
00704     if (pow2Width != surface->resource.width
00705             || pow2Height != surface->resource.height)
00706     {
00707         surface->flags |= SFLAG_NONPOW2;
00708     }
00709 
00710     if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
00711             && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
00712     {
00713         /* One of three options:
00714          * 1: Do the same as we do with NPOT and scale the texture, (any
00715          *    texture ops would require the texture to be scaled which is
00716          *    potentially slow)
00717          * 2: Set the texture to the maximum size (bad idea).
00718          * 3: WARN and return WINED3DERR_NOTAVAILABLE;
00719          * 4: Create the surface, but allow it to be used only for DirectDraw
00720          *    Blts. Some apps (e.g. Swat 3) create textures with a Height of
00721          *    16 and a Width > 3000 and blt 16x16 letter areas from them to
00722          *    the render target. */
00723         if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
00724         {
00725             WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
00726             return WINED3DERR_NOTAVAILABLE;
00727         }
00728 
00729         /* We should never use this surface in combination with OpenGL! */
00730         TRACE("Creating an oversized surface: %ux%u.\n",
00731                 surface->pow2Width, surface->pow2Height);
00732     }
00733     else
00734     {
00735         /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
00736          * and EXT_PALETTED_TEXTURE is used in combination with texture
00737          * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
00738          * EXT_PALETTED_TEXTURE doesn't work in combination with
00739          * ARB_TEXTURE_RECTANGLE. */
00740         if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
00741                 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
00742                 && gl_info->supported[EXT_PALETTED_TEXTURE]
00743                 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
00744         {
00745             surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
00746             surface->pow2Width = surface->resource.width;
00747             surface->pow2Height = surface->resource.height;
00748             surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
00749         }
00750     }
00751 
00752     switch (wined3d_settings.offscreen_rendering_mode)
00753     {
00754         case ORM_FBO:
00755             surface->get_drawable_size = get_drawable_size_fbo;
00756             break;
00757 
00758         case ORM_BACKBUFFER:
00759             surface->get_drawable_size = get_drawable_size_backbuffer;
00760             break;
00761 
00762         default:
00763             ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
00764             return WINED3DERR_INVALIDCALL;
00765     }
00766 
00767     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
00768         surface->flags |= SFLAG_LOST;
00769 
00770     return WINED3D_OK;
00771 }
00772 
00773 static void surface_realize_palette(struct wined3d_surface *surface)
00774 {
00775     struct wined3d_palette *palette = surface->palette;
00776 
00777     TRACE("surface %p.\n", surface);
00778 
00779     if (!palette) return;
00780 
00781     if (surface->resource.format->id == WINED3DFMT_P8_UINT
00782             || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
00783     {
00784         if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
00785         {
00786             /* Make sure the texture is up to date. This call doesn't do
00787              * anything if the texture is already up to date. */
00788             surface_load_location(surface, SFLAG_INTEXTURE, NULL);
00789 
00790             /* We want to force a palette refresh, so mark the drawable as not being up to date */
00791             if (!surface_is_offscreen(surface))
00792                 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
00793         }
00794         else
00795         {
00796             if (!(surface->flags & SFLAG_INSYSMEM))
00797             {
00798                 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
00799                 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
00800             }
00801             surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
00802         }
00803     }
00804 
00805     if (surface->flags & SFLAG_DIBSECTION)
00806     {
00807         RGBQUAD col[256];
00808         unsigned int i;
00809 
00810         TRACE("Updating the DC's palette.\n");
00811 
00812         for (i = 0; i < 256; ++i)
00813         {
00814             col[i].rgbRed   = palette->palents[i].peRed;
00815             col[i].rgbGreen = palette->palents[i].peGreen;
00816             col[i].rgbBlue  = palette->palents[i].peBlue;
00817             col[i].rgbReserved = 0;
00818         }
00819         SetDIBColorTable(surface->hDC, 0, 256, col);
00820     }
00821 
00822     /* Propagate the changes to the drawable when we have a palette. */
00823     if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
00824         surface_load_location(surface, surface->draw_binding, NULL);
00825 }
00826 
00827 static HRESULT surface_draw_overlay(struct wined3d_surface *surface)
00828 {
00829     HRESULT hr;
00830 
00831     /* If there's no destination surface there is nothing to do. */
00832     if (!surface->overlay_dest)
00833         return WINED3D_OK;
00834 
00835     /* Blt calls ModifyLocation on the dest surface, which in turn calls
00836      * DrawOverlay to update the overlay. Prevent an endless recursion. */
00837     if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
00838         return WINED3D_OK;
00839 
00840     surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
00841     hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface,
00842             &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR);
00843     surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
00844 
00845     return hr;
00846 }
00847 
00848 static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
00849 {
00850     struct wined3d_device *device = surface->resource.device;
00851     const RECT *pass_rect = rect;
00852 
00853     TRACE("surface %p, rect %s, flags %#x.\n",
00854             surface, wine_dbgstr_rect(rect), flags);
00855 
00856     if (flags & WINED3DLOCK_DISCARD)
00857     {
00858         TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
00859         surface_prepare_system_memory(surface);
00860         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
00861     }
00862     else
00863     {
00864         /* surface_load_location() does not check if the rectangle specifies
00865          * the full surface. Most callers don't need that, so do it here. */
00866         if (rect && !rect->top && !rect->left
00867                 && rect->right == surface->resource.width
00868                 && rect->bottom == surface->resource.height)
00869             pass_rect = NULL;
00870         surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
00871     }
00872 
00873     if (surface->flags & SFLAG_PBO)
00874     {
00875         const struct wined3d_gl_info *gl_info;
00876         struct wined3d_context *context;
00877 
00878         context = context_acquire(device, NULL);
00879         gl_info = context->gl_info;
00880 
00881         ENTER_GL();
00882         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
00883         checkGLcall("glBindBufferARB");
00884 
00885         /* This shouldn't happen but could occur if some other function
00886          * didn't handle the PBO properly. */
00887         if (surface->resource.allocatedMemory)
00888             ERR("The surface already has PBO memory allocated.\n");
00889 
00890         surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
00891         checkGLcall("glMapBufferARB");
00892 
00893         /* Make sure the PBO isn't set anymore in order not to break non-PBO
00894          * calls. */
00895         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
00896         checkGLcall("glBindBufferARB");
00897 
00898         LEAVE_GL();
00899         context_release(context);
00900     }
00901 
00902     if (!(flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)))
00903     {
00904         if (!rect)
00905             surface_add_dirty_rect(surface, NULL);
00906         else
00907         {
00908             struct wined3d_box b;
00909 
00910             b.left = rect->left;
00911             b.top = rect->top;
00912             b.right = rect->right;
00913             b.bottom = rect->bottom;
00914             b.front = 0;
00915             b.back = 1;
00916             surface_add_dirty_rect(surface, &b);
00917         }
00918     }
00919 }
00920 
00921 static void surface_unmap(struct wined3d_surface *surface)
00922 {
00923     struct wined3d_device *device = surface->resource.device;
00924     BOOL fullsurface;
00925 
00926     TRACE("surface %p.\n", surface);
00927 
00928     memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
00929 
00930     if (surface->flags & SFLAG_PBO)
00931     {
00932         const struct wined3d_gl_info *gl_info;
00933         struct wined3d_context *context;
00934 
00935         TRACE("Freeing PBO memory.\n");
00936 
00937         context = context_acquire(device, NULL);
00938         gl_info = context->gl_info;
00939 
00940         ENTER_GL();
00941         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
00942         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
00943         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
00944         checkGLcall("glUnmapBufferARB");
00945         LEAVE_GL();
00946         context_release(context);
00947 
00948         surface->resource.allocatedMemory = NULL;
00949     }
00950 
00951     TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
00952 
00953     if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
00954     {
00955         TRACE("Not dirtified, nothing to do.\n");
00956         goto done;
00957     }
00958 
00959     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
00960             || (device->fb.render_targets && surface == device->fb.render_targets[0]))
00961     {
00962         if (!surface->dirtyRect.left && !surface->dirtyRect.top
00963                 && surface->dirtyRect.right == surface->resource.width
00964                 && surface->dirtyRect.bottom == surface->resource.height)
00965         {
00966             fullsurface = TRUE;
00967         }
00968         else
00969         {
00970             /* TODO: Proper partial rectangle tracking. */
00971             fullsurface = FALSE;
00972             surface->flags |= SFLAG_INSYSMEM;
00973         }
00974 
00975         surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect);
00976 
00977         /* Partial rectangle tracking is not commonly implemented, it is only
00978          * done for render targets. INSYSMEM was set before to tell
00979          * surface_load_location() where to read the rectangle from.
00980          * Indrawable is set because all modifications from the partial
00981          * sysmem copy are written back to the drawable, thus the surface is
00982          * merged again in the drawable. The sysmem copy is not fully up to
00983          * date because only a subrectangle was read in Map(). */
00984         if (!fullsurface)
00985         {
00986             surface_modify_location(surface, surface->draw_binding, TRUE);
00987             surface_evict_sysmem(surface);
00988         }
00989 
00990         surface->dirtyRect.left = surface->resource.width;
00991         surface->dirtyRect.top = surface->resource.height;
00992         surface->dirtyRect.right = 0;
00993         surface->dirtyRect.bottom = 0;
00994     }
00995     else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
00996     {
00997         FIXME("Depth / stencil buffer locking is not implemented.\n");
00998     }
00999 
01000 done:
01001     /* Overlays have to be redrawn manually after changes with the GL implementation */
01002     if (surface->overlay_dest)
01003         surface_draw_overlay(surface);
01004 }
01005 
01006 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
01007 {
01008     if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
01009         return FALSE;
01010     if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
01011         return FALSE;
01012     return TRUE;
01013 }
01014 
01015 static void wined3d_surface_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_surface *src_surface,
01016         const RECT *src_rect, struct wined3d_surface *dst_surface, const RECT *dst_rect)
01017 {
01018     const struct wined3d_gl_info *gl_info;
01019     struct wined3d_context *context;
01020     DWORD src_mask, dst_mask;
01021     GLbitfield gl_mask;
01022 
01023     TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
01024             device, src_surface, wine_dbgstr_rect(src_rect),
01025             dst_surface, wine_dbgstr_rect(dst_rect));
01026 
01027     src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
01028     dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
01029 
01030     if (src_mask != dst_mask)
01031     {
01032         ERR("Incompatible formats %s and %s.\n",
01033                 debug_d3dformat(src_surface->resource.format->id),
01034                 debug_d3dformat(dst_surface->resource.format->id));
01035         return;
01036     }
01037 
01038     if (!src_mask)
01039     {
01040         ERR("Not a depth / stencil format: %s.\n",
01041                 debug_d3dformat(src_surface->resource.format->id));
01042         return;
01043     }
01044 
01045     gl_mask = 0;
01046     if (src_mask & WINED3DFMT_FLAG_DEPTH)
01047         gl_mask |= GL_DEPTH_BUFFER_BIT;
01048     if (src_mask & WINED3DFMT_FLAG_STENCIL)
01049         gl_mask |= GL_STENCIL_BUFFER_BIT;
01050 
01051     /* Make sure the locations are up-to-date. Loading the destination
01052      * surface isn't required if the entire surface is overwritten. */
01053     surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
01054     if (!surface_is_full_rect(dst_surface, dst_rect))
01055         surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
01056 
01057     context = context_acquire(device, NULL);
01058     if (!context->valid)
01059     {
01060         context_release(context);
01061         WARN("Invalid context, skipping blit.\n");
01062         return;
01063     }
01064 
01065     gl_info = context->gl_info;
01066 
01067     ENTER_GL();
01068 
01069     context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
01070     glReadBuffer(GL_NONE);
01071     checkGLcall("glReadBuffer()");
01072     context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
01073 
01074     context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
01075     context_set_draw_buffer(context, GL_NONE);
01076     context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
01077 
01078     if (gl_mask & GL_DEPTH_BUFFER_BIT)
01079     {
01080         glDepthMask(GL_TRUE);
01081         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
01082     }
01083     if (gl_mask & GL_STENCIL_BUFFER_BIT)
01084     {
01085         if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
01086         {
01087             glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
01088             context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
01089         }
01090         glStencilMask(~0U);
01091         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
01092     }
01093 
01094     glDisable(GL_SCISSOR_TEST);
01095     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
01096 
01097     gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
01098             dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
01099     checkGLcall("glBlitFramebuffer()");
01100 
01101     LEAVE_GL();
01102 
01103     if (wined3d_settings.strict_draw_ordering)
01104         wglFlush(); /* Flush to ensure ordering across contexts. */
01105 
01106     context_release(context);
01107 }
01108 
01109 /* Blit between surface locations. Onscreen on different swapchains is not supported.
01110  * Depth / stencil is not supported. */
01111 static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
01112         struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
01113         struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
01114 {
01115     const struct wined3d_gl_info *gl_info;
01116     struct wined3d_context *context;
01117     RECT src_rect, dst_rect;
01118     GLenum gl_filter;
01119     GLenum buffer;
01120 
01121     TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
01122     TRACE("src_surface %p, src_location %s, src_rect %s,\n",
01123             src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
01124     TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
01125             dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
01126 
01127     src_rect = *src_rect_in;
01128     dst_rect = *dst_rect_in;
01129 
01130     switch (filter)
01131     {
01132         case WINED3D_TEXF_LINEAR:
01133             gl_filter = GL_LINEAR;
01134             break;
01135 
01136         default:
01137             FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
01138         case WINED3D_TEXF_NONE:
01139         case WINED3D_TEXF_POINT:
01140             gl_filter = GL_NEAREST;
01141             break;
01142     }
01143 
01144     /* Resolve the source surface first if needed. */
01145     if (src_location == SFLAG_INRB_MULTISAMPLE
01146             && (src_surface->resource.format->id != dst_surface->resource.format->id
01147                 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
01148                 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
01149         src_location = SFLAG_INRB_RESOLVED;
01150 
01151     /* Make sure the locations are up-to-date. Loading the destination
01152      * surface isn't required if the entire surface is overwritten. (And is
01153      * in fact harmful if we're being called by surface_load_location() with
01154      * the purpose of loading the destination surface.) */
01155     surface_load_location(src_surface, src_location, NULL);
01156     if (!surface_is_full_rect(dst_surface, &dst_rect))
01157         surface_load_location(dst_surface, dst_location, NULL);
01158 
01159     if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
01160     else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
01161     else context = context_acquire(device, NULL);
01162 
01163     if (!context->valid)
01164     {
01165         context_release(context);
01166         WARN("Invalid context, skipping blit.\n");
01167         return;
01168     }
01169 
01170     gl_info = context->gl_info;
01171 
01172     if (src_location == SFLAG_INDRAWABLE)
01173     {
01174         TRACE("Source surface %p is onscreen.\n", src_surface);
01175         buffer = surface_get_gl_buffer(src_surface);
01176         surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
01177     }
01178     else
01179     {
01180         TRACE("Source surface %p is offscreen.\n", src_surface);
01181         buffer = GL_COLOR_ATTACHMENT0;
01182     }
01183 
01184     ENTER_GL();
01185     context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
01186     glReadBuffer(buffer);
01187     checkGLcall("glReadBuffer()");
01188     context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
01189     LEAVE_GL();
01190 
01191     if (dst_location == SFLAG_INDRAWABLE)
01192     {
01193         TRACE("Destination surface %p is onscreen.\n", dst_surface);
01194         buffer = surface_get_gl_buffer(dst_surface);
01195         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
01196     }
01197     else
01198     {
01199         TRACE("Destination surface %p is offscreen.\n", dst_surface);
01200         buffer = GL_COLOR_ATTACHMENT0;
01201     }
01202 
01203     ENTER_GL();
01204     context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
01205     context_set_draw_buffer(context, buffer);
01206     context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
01207     context_invalidate_state(context, STATE_FRAMEBUFFER);
01208 
01209     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
01210     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
01211     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
01212     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
01213     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
01214 
01215     glDisable(GL_SCISSOR_TEST);
01216     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
01217 
01218     gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
01219             dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
01220     checkGLcall("glBlitFramebuffer()");
01221 
01222     LEAVE_GL();
01223 
01224     if (wined3d_settings.strict_draw_ordering
01225             || (dst_location == SFLAG_INDRAWABLE
01226             && dst_surface->container.u.swapchain->front_buffer == dst_surface))
01227         wglFlush();
01228 
01229     context_release(context);
01230 }
01231 
01232 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
01233         const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
01234         const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
01235 {
01236     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
01237         return FALSE;
01238 
01239     /* Source and/or destination need to be on the GL side */
01240     if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
01241         return FALSE;
01242 
01243     switch (blit_op)
01244     {
01245         case WINED3D_BLIT_OP_COLOR_BLIT:
01246             if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
01247                 return FALSE;
01248             if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
01249                 return FALSE;
01250             break;
01251 
01252         case WINED3D_BLIT_OP_DEPTH_BLIT:
01253             if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
01254                 return FALSE;
01255             if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
01256                 return FALSE;
01257             break;
01258 
01259         default:
01260             return FALSE;
01261     }
01262 
01263     if (!(src_format->id == dst_format->id
01264             || (is_identity_fixup(src_format->color_fixup)
01265             && is_identity_fixup(dst_format->color_fixup))))
01266         return FALSE;
01267 
01268     return TRUE;
01269 }
01270 
01271 /* This function checks if the primary render target uses the 8bit paletted format. */
01272 static BOOL primary_render_target_is_p8(const struct wined3d_device *device)
01273 {
01274     if (device->fb.render_targets && device->fb.render_targets[0])
01275     {
01276         const struct wined3d_surface *render_target = device->fb.render_targets[0];
01277         if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
01278                 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
01279             return TRUE;
01280     }
01281     return FALSE;
01282 }
01283 
01284 static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
01285         DWORD color, struct wined3d_color *float_color)
01286 {
01287     const struct wined3d_format *format = surface->resource.format;
01288     const struct wined3d_device *device = surface->resource.device;
01289 
01290     switch (format->id)
01291     {
01292         case WINED3DFMT_P8_UINT:
01293             if (surface->palette)
01294             {
01295                 float_color->r = surface->palette->palents[color].peRed / 255.0f;
01296                 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
01297                 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
01298             }
01299             else
01300             {
01301                 float_color->r = 0.0f;
01302                 float_color->g = 0.0f;
01303                 float_color->b = 0.0f;
01304             }
01305             float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
01306             break;
01307 
01308         case WINED3DFMT_B5G6R5_UNORM:
01309             float_color->r = ((color >> 11) & 0x1f) / 31.0f;
01310             float_color->g = ((color >> 5) & 0x3f) / 63.0f;
01311             float_color->b = (color & 0x1f) / 31.0f;
01312             float_color->a = 1.0f;
01313             break;
01314 
01315         case WINED3DFMT_B8G8R8_UNORM:
01316         case WINED3DFMT_B8G8R8X8_UNORM:
01317             float_color->r = D3DCOLOR_R(color);
01318             float_color->g = D3DCOLOR_G(color);
01319             float_color->b = D3DCOLOR_B(color);
01320             float_color->a = 1.0f;
01321             break;
01322 
01323         case WINED3DFMT_B8G8R8A8_UNORM:
01324             float_color->r = D3DCOLOR_R(color);
01325             float_color->g = D3DCOLOR_G(color);
01326             float_color->b = D3DCOLOR_B(color);
01327             float_color->a = D3DCOLOR_A(color);
01328             break;
01329 
01330         default:
01331             ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
01332             return FALSE;
01333     }
01334 
01335     return TRUE;
01336 }
01337 
01338 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
01339 {
01340     const struct wined3d_format *format = surface->resource.format;
01341 
01342     switch (format->id)
01343     {
01344         case WINED3DFMT_S1_UINT_D15_UNORM:
01345             *float_depth = depth / (float)0x00007fff;
01346             break;
01347 
01348         case WINED3DFMT_D16_UNORM:
01349             *float_depth = depth / (float)0x0000ffff;
01350             break;
01351 
01352         case WINED3DFMT_D24_UNORM_S8_UINT:
01353         case WINED3DFMT_X8D24_UNORM:
01354             *float_depth = depth / (float)0x00ffffff;
01355             break;
01356 
01357         case WINED3DFMT_D32_UNORM:
01358             *float_depth = depth / (float)0xffffffff;
01359             break;
01360 
01361         default:
01362             ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
01363             return FALSE;
01364     }
01365 
01366     return TRUE;
01367 }
01368 
01369 /* Do not call while under the GL lock. */
01370 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
01371 {
01372     const struct wined3d_resource *resource = &surface->resource;
01373     struct wined3d_device *device = resource->device;
01374     const struct blit_shader *blitter;
01375 
01376     blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
01377             NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
01378     if (!blitter)
01379     {
01380         FIXME("No blitter is capable of performing the requested depth fill operation.\n");
01381         return WINED3DERR_INVALIDCALL;
01382     }
01383 
01384     return blitter->depth_fill(device, surface, rect, depth);
01385 }
01386 
01387 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, const RECT *src_rect,
01388         struct wined3d_surface *dst_surface, const RECT *dst_rect)
01389 {
01390     struct wined3d_device *device = src_surface->resource.device;
01391 
01392     if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
01393             src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
01394             dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
01395         return WINED3DERR_INVALIDCALL;
01396 
01397     wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
01398 
01399     surface_modify_ds_location(dst_surface, SFLAG_INTEXTURE,
01400             dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
01401 
01402     return WINED3D_OK;
01403 }
01404 
01405 /* Do not call while under the GL lock. */
01406 HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
01407         struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
01408         const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
01409 {
01410     struct wined3d_swapchain *src_swapchain, *dst_swapchain;
01411     struct wined3d_device *device = dst_surface->resource.device;
01412     DWORD src_ds_flags, dst_ds_flags;
01413     RECT src_rect, dst_rect;
01414     BOOL scale, convert;
01415 
01416     static const DWORD simple_blit = WINEDDBLT_ASYNC
01417             | WINEDDBLT_COLORFILL
01418             | WINEDDBLT_WAIT
01419             | WINEDDBLT_DEPTHFILL
01420             | WINEDDBLT_DONOTWAIT;
01421 
01422     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
01423             dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
01424             flags, fx, debug_d3dtexturefiltertype(filter));
01425     TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
01426 
01427     if (fx)
01428     {
01429         TRACE("dwSize %#x.\n", fx->dwSize);
01430         TRACE("dwDDFX %#x.\n", fx->dwDDFX);
01431         TRACE("dwROP %#x.\n", fx->dwROP);
01432         TRACE("dwDDROP %#x.\n", fx->dwDDROP);
01433         TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
01434         TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
01435         TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
01436         TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
01437         TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
01438         TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
01439         TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
01440         TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
01441         TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
01442         TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
01443         TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
01444         TRACE("dwReserved %#x.\n", fx->dwReserved);
01445         TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
01446         TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
01447         TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
01448         TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
01449         TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
01450         TRACE("ddckDestColorkey {%#x, %#x}.\n",
01451                 fx->ddckDestColorkey.color_space_low_value,
01452                 fx->ddckDestColorkey.color_space_high_value);
01453         TRACE("ddckSrcColorkey {%#x, %#x}.\n",
01454                 fx->ddckSrcColorkey.color_space_low_value,
01455                 fx->ddckSrcColorkey.color_space_high_value);
01456     }
01457 
01458     if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface && (src_surface->flags & SFLAG_LOCKED)))
01459     {
01460         WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
01461         return WINEDDERR_SURFACEBUSY;
01462     }
01463 
01464     surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
01465 
01466     if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
01467             || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
01468             || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
01469             || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
01470             || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
01471     {
01472         WARN("The application gave us a bad destination rectangle.\n");
01473         return WINEDDERR_INVALIDRECT;
01474     }
01475 
01476     if (src_surface)
01477     {
01478         surface_get_rect(src_surface, src_rect_in, &src_rect);
01479 
01480         if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
01481                 || src_rect.left > src_surface->resource.width || src_rect.left < 0
01482                 || src_rect.top > src_surface->resource.height || src_rect.top < 0
01483                 || src_rect.right > src_surface->resource.width || src_rect.right < 0
01484                 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
01485         {
01486             WARN("Application gave us bad source rectangle for Blt.\n");
01487             return WINEDDERR_INVALIDRECT;
01488         }
01489     }
01490     else
01491     {
01492         memset(&src_rect, 0, sizeof(src_rect));
01493     }
01494 
01495     if (!fx || !(fx->dwDDFX))
01496         flags &= ~WINEDDBLT_DDFX;
01497 
01498     if (flags & WINEDDBLT_WAIT)
01499         flags &= ~WINEDDBLT_WAIT;
01500 
01501     if (flags & WINEDDBLT_ASYNC)
01502     {
01503         static unsigned int once;
01504 
01505         if (!once++)
01506             FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
01507         flags &= ~WINEDDBLT_ASYNC;
01508     }
01509 
01510     /* WINEDDBLT_DONOTWAIT appeared in DX7. */
01511     if (flags & WINEDDBLT_DONOTWAIT)
01512     {
01513         static unsigned int once;
01514 
01515         if (!once++)
01516             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
01517         flags &= ~WINEDDBLT_DONOTWAIT;
01518     }
01519 
01520     if (!device->d3d_initialized)
01521     {
01522         WARN("D3D not initialized, using fallback.\n");
01523         goto cpu;
01524     }
01525 
01526     /* We want to avoid invalidating the sysmem location for converted
01527      * surfaces, since otherwise we'd have to convert the data back when
01528      * locking them. */
01529     if (dst_surface->flags & SFLAG_CONVERTED)
01530     {
01531         WARN("Converted surface, using CPU blit.\n");
01532         return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
01533     }
01534 
01535     if (flags & ~simple_blit)
01536     {
01537         WARN("Using fallback for complex blit (%#x).\n", flags);
01538         goto fallback;
01539     }
01540 
01541     if (src_surface && src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
01542         src_swapchain = src_surface->container.u.swapchain;
01543     else
01544         src_swapchain = NULL;
01545 
01546     if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
01547         dst_swapchain = dst_surface->container.u.swapchain;
01548     else
01549         dst_swapchain = NULL;
01550 
01551     /* This isn't strictly needed. FBO blits for example could deal with
01552      * cross-swapchain blits by first downloading the source to a texture
01553      * before switching to the destination context. We just have this here to
01554      * not have to deal with the issue, since cross-swapchain blits should be
01555      * rare. */
01556     if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
01557     {
01558         FIXME("Using fallback for cross-swapchain blit.\n");
01559         goto fallback;
01560     }
01561 
01562     scale = src_surface
01563             && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
01564             || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
01565     convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
01566 
01567     dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
01568     if (src_surface)
01569         src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
01570     else
01571         src_ds_flags = 0;
01572 
01573     if (src_ds_flags || dst_ds_flags)
01574     {
01575         if (flags & WINEDDBLT_DEPTHFILL)
01576         {
01577             float depth;
01578 
01579             TRACE("Depth fill.\n");
01580 
01581             if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
01582                 return WINED3DERR_INVALIDCALL;
01583 
01584             if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
01585                 return WINED3D_OK;
01586         }
01587         else
01588         {
01589             /* Accessing depth / stencil surfaces is supposed to fail while in
01590              * a scene, except for fills, which seem to work. */
01591             if (device->inScene)
01592             {
01593                 WARN("Rejecting depth / stencil access while in scene.\n");
01594                 return WINED3DERR_INVALIDCALL;
01595             }
01596 
01597             if (src_ds_flags != dst_ds_flags)
01598             {
01599                 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
01600                 return WINED3DERR_INVALIDCALL;
01601             }
01602 
01603             if (src_rect.top || src_rect.left
01604                     || src_rect.bottom != src_surface->resource.height
01605                     || src_rect.right != src_surface->resource.width)
01606             {
01607                 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
01608                         wine_dbgstr_rect(&src_rect));
01609                 return WINED3DERR_INVALIDCALL;
01610             }
01611 
01612             if (dst_rect.top || dst_rect.left
01613                     || dst_rect.bottom != dst_surface->resource.height
01614                     || dst_rect.right != dst_surface->resource.width)
01615             {
01616                 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
01617                         wine_dbgstr_rect(&src_rect));
01618                 return WINED3DERR_INVALIDCALL;
01619             }
01620 
01621             if (scale)
01622             {
01623                 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
01624                 return WINED3DERR_INVALIDCALL;
01625             }
01626 
01627             if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, &src_rect, dst_surface, &dst_rect)))
01628                 return WINED3D_OK;
01629         }
01630     }
01631     else
01632     {
01633         /* In principle this would apply to depth blits as well, but we don't
01634          * implement those in the CPU blitter at the moment. */
01635         if ((dst_surface->flags & SFLAG_INSYSMEM)
01636                 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM)))
01637         {
01638             if (scale)
01639                 TRACE("Not doing sysmem blit because of scaling.\n");
01640             else if (convert)
01641                 TRACE("Not doing sysmem blit because of format conversion.\n");
01642             else
01643                 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
01644         }
01645 
01646         if (flags & WINEDDBLT_COLORFILL)
01647         {
01648             struct wined3d_color color;
01649 
01650             TRACE("Color fill.\n");
01651 
01652             if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
01653                 goto fallback;
01654 
01655             if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
01656                 return WINED3D_OK;
01657         }
01658         else
01659         {
01660             TRACE("Color blit.\n");
01661 
01662             /* Upload */
01663             if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM))
01664             {
01665                 if (scale)
01666                     TRACE("Not doing upload because of scaling.\n");
01667                 else if (convert)
01668                     TRACE("Not doing upload because of format conversion.\n");
01669                 else
01670                 {
01671                     POINT dst_point = {dst_rect.left, dst_rect.top};
01672 
01673                     if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
01674                     {
01675                         if (!surface_is_offscreen(dst_surface))
01676                             surface_load_location(dst_surface, dst_surface->draw_binding, NULL);
01677                         return WINED3D_OK;
01678                     }
01679                 }
01680             }
01681 
01682             /* Use present for back -> front blits. The idea behind this is
01683              * that present is potentially faster than a blit, in particular
01684              * when FBO blits aren't available. Some ddraw applications like
01685              * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
01686              * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
01687              * applications can't blit directly to the frontbuffer. */
01688             if (dst_swapchain && dst_swapchain->back_buffers
01689                     && dst_surface == dst_swapchain->front_buffer
01690                     && src_surface == dst_swapchain->back_buffers[0])
01691             {
01692                 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
01693 
01694                 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
01695 
01696                 /* Set the swap effect to COPY, we don't want the backbuffer
01697                  * to become undefined. */
01698                 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
01699                 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
01700                 dst_swapchain->desc.swap_effect = swap_effect;
01701 
01702                 return WINED3D_OK;
01703             }
01704 
01705             if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
01706                     &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
01707                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
01708             {
01709                 TRACE("Using FBO blit.\n");
01710 
01711                 surface_blt_fbo(device, filter,
01712                         src_surface, src_surface->draw_binding, &src_rect,
01713                         dst_surface, dst_surface->draw_binding, &dst_rect);
01714                 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
01715                 return WINED3D_OK;
01716             }
01717 
01718             if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
01719                     &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
01720                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
01721             {
01722                 TRACE("Using arbfp blit.\n");
01723 
01724                 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
01725                     return WINED3D_OK;
01726             }
01727         }
01728     }
01729 
01730 fallback:
01731 
01732     /* Special cases for render targets. */
01733     if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
01734             || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
01735     {
01736         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect,
01737                 src_surface, &src_rect, flags, fx, filter)))
01738             return WINED3D_OK;
01739     }
01740 
01741 cpu:
01742 
01743     /* For the rest call the X11 surface implementation. For render targets
01744      * this should be implemented OpenGL accelerated in BltOverride, other
01745      * blits are rather rare. */
01746     return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
01747 }
01748 
01749 HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
01750         struct wined3d_surface *render_target)
01751 {
01752     TRACE("surface %p, render_target %p.\n", surface, render_target);
01753 
01754     /* TODO: Check surface sizes, pools, etc. */
01755 
01756     if (render_target->resource.multisample_type)
01757         return WINED3DERR_INVALIDCALL;
01758 
01759     return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
01760 }
01761 
01762 /* Context activation is done by the caller. */
01763 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
01764 {
01765     if (surface->flags & SFLAG_DIBSECTION)
01766     {
01767         surface->resource.allocatedMemory = surface->dib.bitmap_data;
01768     }
01769     else
01770     {
01771         if (!surface->resource.heapMemory)
01772             surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
01773         else if (!(surface->flags & SFLAG_CLIENT))
01774             ERR("Surface %p has heapMemory %p and flags %#x.\n",
01775                     surface, surface->resource.heapMemory, surface->flags);
01776 
01777         surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
01778                 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
01779     }
01780 
01781     ENTER_GL();
01782     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
01783     checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
01784     GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
01785             surface->resource.size, surface->resource.allocatedMemory));
01786     checkGLcall("glGetBufferSubDataARB");
01787     GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
01788     checkGLcall("glDeleteBuffersARB");
01789     LEAVE_GL();
01790 
01791     surface->pbo = 0;
01792     surface->flags &= ~SFLAG_PBO;
01793 }
01794 
01795 /* Do not call while under the GL lock. */
01796 static void surface_unload(struct wined3d_resource *resource)
01797 {
01798     struct wined3d_surface *surface = surface_from_resource(resource);
01799     struct wined3d_renderbuffer_entry *entry, *entry2;
01800     struct wined3d_device *device = resource->device;
01801     const struct wined3d_gl_info *gl_info;
01802     struct wined3d_context *context;
01803 
01804     TRACE("surface %p.\n", surface);
01805 
01806     if (resource->pool == WINED3D_POOL_DEFAULT)
01807     {
01808         /* Default pool resources are supposed to be destroyed before Reset is called.
01809          * Implicit resources stay however. So this means we have an implicit render target
01810          * or depth stencil. The content may be destroyed, but we still have to tear down
01811          * opengl resources, so we cannot leave early.
01812          *
01813          * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
01814          * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
01815          * or the depth stencil into an FBO the texture or render buffer will be removed
01816          * and all flags get lost
01817          */
01818         if (!(surface->flags & SFLAG_PBO))
01819             surface_init_sysmem(surface);
01820         /* We also get here when the ddraw swapchain is destroyed, for example
01821          * for a mode switch. In this case this surface won't necessarily be
01822          * an implicit surface. We have to mark it lost so that the
01823          * application can restore it after the mode switch. */
01824         surface->flags |= SFLAG_LOST;
01825     }
01826     else
01827     {
01828         /* Load the surface into system memory */
01829         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
01830         surface_modify_location(surface, surface->draw_binding, FALSE);
01831     }
01832     surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
01833     surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
01834     surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
01835 
01836     context = context_acquire(device, NULL);
01837     gl_info = context->gl_info;
01838 
01839     /* Destroy PBOs, but load them into real sysmem before */
01840     if (surface->flags & SFLAG_PBO)
01841         surface_remove_pbo(surface, gl_info);
01842 
01843     /* Destroy fbo render buffers. This is needed for implicit render targets, for
01844      * all application-created targets the application has to release the surface
01845      * before calling _Reset
01846      */
01847     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
01848     {
01849         ENTER_GL();
01850         gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
01851         LEAVE_GL();
01852         list_remove(&entry->entry);
01853         HeapFree(GetProcessHeap(), 0, entry);
01854     }
01855     list_init(&surface->renderbuffers);
01856     surface->current_renderbuffer = NULL;
01857 
01858     ENTER_GL();
01859 
01860     /* If we're in a texture, the texture name belongs to the texture.
01861      * Otherwise, destroy it. */
01862     if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
01863     {
01864         glDeleteTextures(1, &surface->texture_name);
01865         surface->texture_name = 0;
01866         glDeleteTextures(1, &surface->texture_name_srgb);
01867         surface->texture_name_srgb = 0;
01868     }
01869     if (surface->rb_multisample)
01870     {
01871         gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
01872         surface->rb_multisample = 0;
01873     }
01874     if (surface->rb_resolved)
01875     {
01876         gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
01877         surface->rb_resolved = 0;
01878     }
01879 
01880     LEAVE_GL();
01881 
01882     context_release(context);
01883 
01884     resource_unload(resource);
01885 }
01886 
01887 static const struct wined3d_resource_ops surface_resource_ops =
01888 {
01889     surface_unload,
01890 };
01891 
01892 static const struct wined3d_surface_ops surface_ops =
01893 {
01894     surface_private_setup,
01895     surface_realize_palette,
01896     surface_map,
01897     surface_unmap,
01898 };
01899 
01900 /*****************************************************************************
01901  * Initializes the GDI surface, aka creates the DIB section we render to
01902  * The DIB section creation is done by calling GetDC, which will create the
01903  * section and releasing the dc to allow the app to use it. The dib section
01904  * will stay until the surface is released
01905  *
01906  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
01907  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
01908  * avoid confusion in the shared surface code.
01909  *
01910  * Returns:
01911  *  WINED3D_OK on success
01912  *  The return values of called methods on failure
01913  *
01914  *****************************************************************************/
01915 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
01916 {
01917     HRESULT hr;
01918 
01919     TRACE("surface %p.\n", surface);
01920 
01921     if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
01922     {
01923         ERR("Overlays not yet supported by GDI surfaces.\n");
01924         return WINED3DERR_INVALIDCALL;
01925     }
01926 
01927     /* Sysmem textures have memory already allocated - release it,
01928      * this avoids an unnecessary memcpy. */
01929     hr = surface_create_dib_section(surface);
01930     if (SUCCEEDED(hr))
01931     {
01932         HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
01933         surface->resource.heapMemory = NULL;
01934         surface->resource.allocatedMemory = surface->dib.bitmap_data;
01935     }
01936 
01937     /* We don't mind the nonpow2 stuff in GDI. */
01938     surface->pow2Width = surface->resource.width;
01939     surface->pow2Height = surface->resource.height;
01940 
01941     return WINED3D_OK;
01942 }
01943 
01944 static void gdi_surface_realize_palette(struct wined3d_surface *surface)
01945 {
01946     struct wined3d_palette *palette = surface->palette;
01947 
01948     TRACE("surface %p.\n", surface);
01949 
01950     if (!palette) return;
01951 
01952     if (surface->flags & SFLAG_DIBSECTION)
01953     {
01954         RGBQUAD col[256];
01955         unsigned int i;
01956 
01957         TRACE("Updating the DC's palette.\n");
01958 
01959         for (i = 0; i < 256; ++i)
01960         {
01961             col[i].rgbRed = palette->palents[i].peRed;
01962             col[i].rgbGreen = palette->palents[i].peGreen;
01963             col[i].rgbBlue = palette->palents[i].peBlue;
01964             col[i].rgbReserved = 0;
01965         }
01966         SetDIBColorTable(surface->hDC, 0, 256, col);
01967     }
01968 
01969     /* Update the image because of the palette change. Some games like e.g.
01970      * Red Alert call SetEntries a lot to implement fading. */
01971     /* Tell the swapchain to update the screen. */
01972     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
01973     {
01974         struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
01975         if (surface == swapchain->front_buffer)
01976         {
01977             x11_copy_to_screen(swapchain, NULL);
01978         }
01979     }
01980 }
01981 
01982 static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
01983 {
01984     TRACE("surface %p, rect %s, flags %#x.\n",
01985             surface, wine_dbgstr_rect(rect), flags);
01986 
01987     if (!(surface->flags & SFLAG_DIBSECTION))
01988     {
01989         /* This happens on gdi surfaces if the application set a user pointer
01990          * and resets it. Recreate the DIB section. */
01991         surface_create_dib_section(surface);
01992         surface->resource.allocatedMemory = surface->dib.bitmap_data;
01993     }
01994 }
01995 
01996 static void gdi_surface_unmap(struct wined3d_surface *surface)
01997 {
01998     TRACE("surface %p.\n", surface);
01999 
02000     /* Tell the swapchain to update the screen. */
02001     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
02002     {
02003         struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
02004         if (surface == swapchain->front_buffer)
02005         {
02006             x11_copy_to_screen(swapchain, &surface->lockedRect);
02007         }
02008     }
02009 
02010     memset(&surface->lockedRect, 0, sizeof(RECT));
02011 }
02012 
02013 static const struct wined3d_surface_ops gdi_surface_ops =
02014 {
02015     gdi_surface_private_setup,
02016     gdi_surface_realize_palette,
02017     gdi_surface_map,
02018     gdi_surface_unmap,
02019 };
02020 
02021 void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb)
02022 {
02023     GLuint *name;
02024     DWORD flag;
02025 
02026     TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
02027 
02028     if(srgb)
02029     {
02030         name = &surface->texture_name_srgb;
02031         flag = SFLAG_INSRGBTEX;
02032     }
02033     else
02034     {
02035         name = &surface->texture_name;
02036         flag = SFLAG_INTEXTURE;
02037     }
02038 
02039     if (!*name && new_name)
02040     {
02041         /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
02042          * surface has no texture name yet. See if we can get rid of this. */
02043         if (surface->flags & flag)
02044         {
02045             ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
02046             surface_modify_location(surface, flag, FALSE);
02047         }
02048     }
02049 
02050     *name = new_name;
02051     surface_force_reload(surface);
02052 }
02053 
02054 void surface_set_texture_target(struct wined3d_surface *surface, GLenum target)
02055 {
02056     TRACE("surface %p, target %#x.\n", surface, target);
02057 
02058     if (surface->texture_target != target)
02059     {
02060         if (target == GL_TEXTURE_RECTANGLE_ARB)
02061         {
02062             surface->flags &= ~SFLAG_NORMCOORD;
02063         }
02064         else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
02065         {
02066             surface->flags |= SFLAG_NORMCOORD;
02067         }
02068     }
02069     surface->texture_target = target;
02070     surface_force_reload(surface);
02071 }
02072 
02073 /* Context activation is done by the caller. */
02074 void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
02075 {
02076     TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb);
02077 
02078     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
02079     {
02080         struct wined3d_texture *texture = surface->container.u.texture;
02081 
02082         TRACE("Passing to container (%p).\n", texture);
02083         texture->texture_ops->texture_bind(texture, context, srgb);
02084     }
02085     else
02086     {
02087         if (surface->texture_level)
02088         {
02089             ERR("Standalone surface %p is non-zero texture level %u.\n",
02090                     surface, surface->texture_level);
02091         }
02092 
02093         if (srgb)
02094             ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
02095 
02096         ENTER_GL();
02097 
02098         if (!surface->texture_name)
02099         {
02100             glGenTextures(1, &surface->texture_name);
02101             checkGLcall("glGenTextures");
02102 
02103             TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
02104 
02105             context_bind_texture(context, surface->texture_target, surface->texture_name);
02106             glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
02107             glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
02108             glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
02109             glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
02110             glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
02111             checkGLcall("glTexParameteri");
02112         }
02113         else
02114         {
02115             context_bind_texture(context, surface->texture_target, surface->texture_name);
02116         }
02117 
02118         LEAVE_GL();
02119     }
02120 }
02121 
02122 /* This call just downloads data, the caller is responsible for binding the
02123  * correct texture. */
02124 /* Context activation is done by the caller. */
02125 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
02126 {
02127     const struct wined3d_format *format = surface->resource.format;
02128 
02129     /* Only support read back of converted P8 surfaces. */
02130     if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
02131     {
02132         ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
02133         return;
02134     }
02135 
02136     ENTER_GL();
02137 
02138     if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
02139     {
02140         TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
02141                 surface, surface->texture_level, format->glFormat, format->glType,
02142                 surface->resource.allocatedMemory);
02143 
02144         if (surface->flags & SFLAG_PBO)
02145         {
02146             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
02147             checkGLcall("glBindBufferARB");
02148             GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
02149             checkGLcall("glGetCompressedTexImageARB");
02150             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
02151             checkGLcall("glBindBufferARB");
02152         }
02153         else
02154         {
02155             GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
02156                     surface->texture_level, surface->resource.allocatedMemory));
02157             checkGLcall("glGetCompressedTexImageARB");
02158         }
02159 
02160         LEAVE_GL();
02161     }
02162     else
02163     {
02164         void *mem;
02165         GLenum gl_format = format->glFormat;
02166         GLenum gl_type = format->glType;
02167         int src_pitch = 0;
02168         int dst_pitch = 0;
02169 
02170         /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
02171         if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
02172         {
02173             gl_format = GL_ALPHA;
02174             gl_type = GL_UNSIGNED_BYTE;
02175         }
02176 
02177         if (surface->flags & SFLAG_NONPOW2)
02178         {
02179             unsigned char alignment = surface->resource.device->surface_alignment;
02180             src_pitch = format->byte_count * surface->pow2Width;
02181             dst_pitch = wined3d_surface_get_pitch(surface);
02182             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
02183             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
02184         }
02185         else
02186         {
02187             mem = surface->resource.allocatedMemory;
02188         }
02189 
02190         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
02191                 surface, surface->texture_level, gl_format, gl_type, mem);
02192 
02193         if (surface->flags & SFLAG_PBO)
02194         {
02195             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
02196             checkGLcall("glBindBufferARB");
02197 
02198             glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, NULL);
02199             checkGLcall("glGetTexImage");
02200 
02201             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
02202             checkGLcall("glBindBufferARB");
02203         }
02204         else
02205         {
02206             glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, mem);
02207             checkGLcall("glGetTexImage");
02208         }
02209         LEAVE_GL();
02210 
02211         if (surface->flags & SFLAG_NONPOW2)
02212         {
02213             const BYTE *src_data;
02214             BYTE *dst_data;
02215             UINT y;
02216             /*
02217              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
02218              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
02219              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
02220              *
02221              * We're doing this...
02222              *
02223              * instead of boxing the texture :
02224              * |<-texture width ->|  -->pow2width|   /\
02225              * |111111111111111111|              |   |
02226              * |222 Texture 222222| boxed empty  | texture height
02227              * |3333 Data 33333333|              |   |
02228              * |444444444444444444|              |   \/
02229              * -----------------------------------   |
02230              * |     boxed  empty | boxed empty  | pow2height
02231              * |                  |              |   \/
02232              * -----------------------------------
02233              *
02234              *
02235              * we're repacking the data to the expected texture width
02236              *
02237              * |<-texture width ->|  -->pow2width|   /\
02238              * |111111111111111111222222222222222|   |
02239              * |222333333333333333333444444444444| texture height
02240              * |444444                           |   |
02241              * |                                 |   \/
02242              * |                                 |   |
02243              * |            empty                | pow2height
02244              * |                                 |   \/
02245              * -----------------------------------
02246              *
02247              * == is the same as
02248              *
02249              * |<-texture width ->|    /\
02250              * |111111111111111111|
02251              * |222222222222222222|texture height
02252              * |333333333333333333|
02253              * |444444444444444444|    \/
02254              * --------------------
02255              *
02256              * this also means that any references to allocatedMemory should work with the data as if were a
02257              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
02258              *
02259              * internally the texture is still stored in a boxed format so any references to textureName will
02260              * get a boxed texture with width pow2width and not a texture of width resource.width.
02261              *
02262              * Performance should not be an issue, because applications normally do not lock the surfaces when
02263              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
02264              * and doesn't have to be re-read. */
02265             src_data = mem;
02266             dst_data = surface->resource.allocatedMemory;
02267             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
02268             for (y = 1; y < surface->resource.height; ++y)
02269             {
02270                 /* skip the first row */
02271                 src_data += src_pitch;
02272                 dst_data += dst_pitch;
02273                 memcpy(dst_data, src_data, dst_pitch);
02274             }
02275 
02276             HeapFree(GetProcessHeap(), 0, mem);
02277         }
02278     }
02279 
02280     /* Surface has now been downloaded */
02281     surface->flags |= SFLAG_INSYSMEM;
02282 }
02283 
02284 /* This call just uploads data, the caller is responsible for binding the
02285  * correct texture. */
02286 /* Context activation is done by the caller. */
02287 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
02288         const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
02289         BOOL srgb, const struct wined3d_bo_address *data)
02290 {
02291     UINT update_w = src_rect->right - src_rect->left;
02292     UINT update_h = src_rect->bottom - src_rect->top;
02293 
02294     TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
02295             surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
02296             wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
02297 
02298     if (surface->flags & SFLAG_LOCKED)
02299     {
02300         WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
02301         surface->flags |= SFLAG_PIN_SYSMEM;
02302     }
02303 
02304     if (format->heightscale != 1.0f && format->heightscale != 0.0f)
02305         update_h *= format->heightscale;
02306 
02307     ENTER_GL();
02308 
02309     if (data->buffer_object)
02310     {
02311         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
02312         checkGLcall("glBindBufferARB");
02313     }
02314 
02315     if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
02316     {
02317         UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
02318         UINT row_count = (update_h + format->block_height - 1) / format->block_height;
02319         const BYTE *addr = data->addr;
02320         GLenum internal;
02321 
02322         addr += (src_rect->top / format->block_height) * src_pitch;
02323         addr += (src_rect->left / format->block_width) * format->block_byte_count;
02324 
02325         if (srgb)
02326             internal = format->glGammaInternal;
02327         else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
02328             internal = format->rtInternal;
02329         else
02330             internal = format->glInternal;
02331 
02332         TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
02333                 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
02334                 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
02335 
02336         if (row_length == src_pitch)
02337         {
02338             GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
02339                     dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
02340         }
02341         else
02342         {
02343             UINT row, y;
02344 
02345             /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
02346              * can't use the unpack row length like below. */
02347             for (row = 0, y = dst_point->y; row < row_count; ++row)
02348             {
02349                 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
02350                         dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
02351                 y += format->block_height;
02352                 addr += src_pitch;
02353             }
02354         }
02355         checkGLcall("glCompressedTexSubImage2DARB");
02356     }
02357     else
02358     {
02359         const BYTE *addr = data->addr;
02360 
02361         addr += src_rect->top * src_pitch;
02362         addr += src_rect->left * format->byte_count;
02363 
02364         TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
02365                 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
02366                 update_w, update_h, format->glFormat, format->glType, addr);
02367 
02368         glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
02369         glTexSubImage2D(surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
02370                 update_w, update_h, format->glFormat, format->glType, addr);
02371         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
02372         checkGLcall("glTexSubImage2D");
02373     }
02374 
02375     if (data->buffer_object)
02376     {
02377         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
02378         checkGLcall("glBindBufferARB");
02379     }
02380 
02381     LEAVE_GL();
02382 
02383     if (wined3d_settings.strict_draw_ordering)
02384         wglFlush();
02385 
02386     if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
02387     {
02388         struct wined3d_device *device = surface->resource.device;
02389         unsigned int i;
02390 
02391         for (i = 0; i < device->context_count; ++i)
02392         {
02393             context_surface_update(device->contexts[i], surface);
02394         }
02395     }
02396 }
02397 
02398 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
02399         struct wined3d_surface *src_surface, const RECT *src_rect)
02400 {
02401     const struct wined3d_format *src_format;
02402     const struct wined3d_format *dst_format;
02403     const struct wined3d_gl_info *gl_info;
02404     struct wined3d_context *context;
02405     struct wined3d_bo_address data;
02406     struct wined3d_format format;
02407     UINT update_w, update_h;
02408     CONVERT_TYPES convert;
02409     UINT dst_w, dst_h;
02410     UINT src_w, src_h;
02411     UINT src_pitch;
02412     POINT p;
02413     RECT r;
02414 
02415     TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
02416             dst_surface, wine_dbgstr_point(dst_point),
02417             src_surface, wine_dbgstr_rect(src_rect));
02418 
02419     src_format = src_surface->resource.format;
02420     dst_format = dst_surface->resource.format;
02421 
02422     if (src_format->id != dst_format->id)
02423     {
02424         WARN("Source and destination surfaces should have the same format.\n");
02425         return WINED3DERR_INVALIDCALL;
02426     }
02427 
02428     if (!dst_point)
02429     {
02430         p.x = 0;
02431         p.y = 0;
02432         dst_point = &p;
02433     }
02434     else if (dst_point->x < 0 || dst_point->y < 0)
02435     {
02436         WARN("Invalid destination point.\n");
02437         return WINED3DERR_INVALIDCALL;
02438     }
02439 
02440     if (!src_rect)
02441     {
02442         r.left = 0;
02443         r.top = 0;
02444         r.right = src_surface->resource.width;
02445         r.bottom = src_surface->resource.height;
02446         src_rect = &r;
02447     }
02448     else if (src_rect->left < 0 || src_rect->left >= src_rect->right
02449             || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
02450     {
02451         WARN("Invalid source rectangle.\n");
02452         return WINED3DERR_INVALIDCALL;
02453     }
02454 
02455     src_w = src_surface->resource.width;
02456     src_h = src_surface->resource.height;
02457 
02458     dst_w = dst_surface->resource.width;
02459     dst_h = dst_surface->resource.height;
02460 
02461     update_w = src_rect->right - src_rect->left;
02462     update_h = src_rect->bottom - src_rect->top;
02463 
02464     if (update_w > dst_w || dst_point->x > dst_w - update_w
02465             || update_h > dst_h || dst_point->y > dst_h - update_h)
02466     {
02467         WARN("Destination out of bounds.\n");
02468         return WINED3DERR_INVALIDCALL;
02469     }
02470 
02471     /* NPOT block sizes would be silly. */
02472     if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS)
02473             && ((update_w & (src_format->block_width - 1) || update_h & (src_format->block_height - 1))
02474             && (src_w != update_w || dst_w != update_w || src_h != update_h || dst_h != update_h)))
02475     {
02476         WARN("Update rect not block-aligned.\n");
02477         return WINED3DERR_INVALIDCALL;
02478     }
02479 
02480     /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
02481     d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
02482     if (convert != NO_CONVERSION || format.convert)
02483     {
02484         RECT dst_rect = {dst_point->x,  dst_point->y, dst_point->x + update_w, dst_point->y + update_h};
02485         return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
02486     }
02487 
02488     context = context_acquire(dst_surface->resource.device, NULL);
02489     gl_info = context->gl_info;
02490 
02491     /* Only load the surface for partial updates. For newly allocated texture
02492      * the texture wouldn't be the current location, and we'd upload zeroes
02493      * just to overwrite them again. */
02494     if (update_w == dst_w && update_h == dst_h)
02495         surface_prepare_texture(dst_surface, context, FALSE);
02496     else
02497         surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
02498     surface_bind(dst_surface, context, FALSE);
02499 
02500     data.buffer_object = src_surface->pbo;
02501     data.addr = src_surface->resource.allocatedMemory;
02502     src_pitch = wined3d_surface_get_pitch(src_surface);
02503 
02504     surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
02505 
02506     invalidate_active_texture(dst_surface->resource.device, context);
02507 
02508     context_release(context);
02509 
02510     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
02511     return WINED3D_OK;
02512 }
02513 
02514 /* This call just allocates the texture, the caller is responsible for binding
02515  * the correct texture. */
02516 /* Context activation is done by the caller. */
02517 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
02518         const struct wined3d_format *format, BOOL srgb)
02519 {
02520     BOOL enable_client_storage = FALSE;
02521     GLsizei width = surface->pow2Width;
02522     GLsizei height = surface->pow2Height;
02523     const BYTE *mem = NULL;
02524     GLenum internal;
02525 
02526     if (srgb)
02527     {
02528         internal = format->glGammaInternal;
02529     }
02530     else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
02531     {
02532         internal = format->rtInternal;
02533     }
02534     else
02535     {
02536         internal = format->glInternal;
02537     }
02538 
02539     if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
02540 
02541     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",
02542             surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
02543             internal, width, height, format->glFormat, format->glType);
02544 
02545     ENTER_GL();
02546 
02547     if (gl_info->supported[APPLE_CLIENT_STORAGE])
02548     {
02549         if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
02550                 || !surface->resource.allocatedMemory)
02551         {
02552             /* In some cases we want to disable client storage.
02553              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
02554              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
02555              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
02556              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
02557              */
02558             glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
02559             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
02560             surface->flags &= ~SFLAG_CLIENT;
02561             enable_client_storage = TRUE;
02562         }
02563         else
02564         {
02565             surface->flags |= SFLAG_CLIENT;
02566 
02567             /* Point OpenGL to our allocated texture memory. Do not use
02568              * resource.allocatedMemory here because it might point into a
02569              * PBO. Instead use heapMemory, but get the alignment right. */
02570             mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
02571                     + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
02572         }
02573     }
02574 
02575     if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
02576     {
02577         GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
02578                 internal, width, height, 0, surface->resource.size, mem));
02579         checkGLcall("glCompressedTexImage2DARB");
02580     }
02581     else
02582     {
02583         glTexImage2D(surface->texture_target, surface->texture_level,
02584                 internal, width, height, 0, format->glFormat, format->glType, mem);
02585         checkGLcall("glTexImage2D");
02586     }
02587 
02588     if(enable_client_storage) {
02589         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
02590         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
02591     }
02592     LEAVE_GL();
02593 }
02594 
02595 /* In D3D the depth stencil dimensions have to be greater than or equal to the
02596  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
02597 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
02598 /* GL locking is done by the caller */
02599 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
02600 {
02601     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
02602     struct wined3d_renderbuffer_entry *entry;
02603     GLuint renderbuffer = 0;
02604     unsigned int src_width, src_height;
02605     unsigned int width, height;
02606 
02607     if (rt && rt->resource.format->id != WINED3DFMT_NULL)
02608     {
02609         width = rt->pow2Width;
02610         height = rt->pow2Height;
02611     }
02612     else
02613     {
02614         width = surface->pow2Width;
02615         height = surface->pow2Height;
02616     }
02617 
02618     src_width = surface->pow2Width;
02619     src_height = surface->pow2Height;
02620 
02621     /* A depth stencil smaller than the render target is not valid */
02622     if (width > src_width || height > src_height) return;
02623 
02624     /* Remove any renderbuffer set if the sizes match */
02625     if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
02626             || (width == src_width && height == src_height))
02627     {
02628         surface->current_renderbuffer = NULL;
02629         return;
02630     }
02631 
02632     /* Look if we've already got a renderbuffer of the correct dimensions */
02633     LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
02634     {
02635         if (entry->width == width && entry->height == height)
02636         {
02637             renderbuffer = entry->id;
02638             surface->current_renderbuffer = entry;
02639             break;
02640         }
02641     }
02642 
02643     if (!renderbuffer)
02644     {
02645         gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
02646         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
02647         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
02648                 surface->resource.format->glInternal, width, height);
02649 
02650         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
02651         entry->width = width;
02652         entry->height = height;
02653         entry->id = renderbuffer;
02654         list_add_head(&surface->renderbuffers, &entry->entry);
02655 
02656         surface->current_renderbuffer = entry;
02657     }
02658 
02659     checkGLcall("set_compatible_renderbuffer");
02660 }
02661 
02662 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
02663 {
02664     const struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
02665 
02666     TRACE("surface %p.\n", surface);
02667 
02668     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
02669     {
02670         ERR("Surface %p is not on a swapchain.\n", surface);
02671         return GL_NONE;
02672     }
02673 
02674     if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
02675     {
02676         if (swapchain->render_to_fbo)
02677         {
02678             TRACE("Returning GL_COLOR_ATTACHMENT0\n");
02679             return GL_COLOR_ATTACHMENT0;
02680         }
02681         TRACE("Returning GL_BACK\n");
02682         return GL_BACK;
02683     }
02684     else if (surface == swapchain->front_buffer)
02685     {
02686         TRACE("Returning GL_FRONT\n");
02687         return GL_FRONT;
02688     }
02689 
02690     FIXME("Higher back buffer, returning GL_BACK\n");
02691     return GL_BACK;
02692 }
02693 
02694 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
02695 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
02696 {
02697     TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
02698 
02699     if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
02700         /* No partial locking for textures yet. */
02701         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
02702 
02703     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
02704     if (dirty_rect)
02705     {
02706         surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
02707         surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
02708         surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
02709         surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
02710     }
02711     else
02712     {
02713         surface->dirtyRect.left = 0;
02714         surface->dirtyRect.top = 0;
02715         surface->dirtyRect.right = surface->resource.width;
02716         surface->dirtyRect.bottom = surface->resource.height;
02717     }
02718 
02719     /* if the container is a texture then mark it dirty. */
02720     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
02721     {
02722         TRACE("Passing to container.\n");
02723         wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
02724     }
02725 }
02726 
02727 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
02728 {
02729     DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
02730     BOOL ck_changed;
02731 
02732     TRACE("surface %p, srgb %#x.\n", surface, srgb);
02733 
02734     if (surface->resource.pool == WINED3D_POOL_SCRATCH)
02735     {
02736         ERR("Not supported on scratch surfaces.\n");
02737         return WINED3DERR_INVALIDCALL;
02738     }
02739 
02740     ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
02741 
02742     /* Reload if either the texture and sysmem have different ideas about the
02743      * color key, or the actual key values changed. */
02744     if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
02745             && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
02746             || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
02747     {
02748         TRACE("Reloading because of color keying\n");
02749         /* To perform the color key conversion we need a sysmem copy of
02750          * the surface. Make sure we have it. */
02751 
02752         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
02753         /* Make sure the texture is reloaded because of the color key change,
02754          * this kills performance though :( */
02755         /* TODO: This is not necessarily needed with hw palettized texture support. */
02756         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
02757         /* Switching color keying on / off may change the internal format. */
02758         if (ck_changed)
02759             surface_force_reload(surface);
02760     }
02761     else if (!(surface->flags & flag))
02762     {
02763         TRACE("Reloading because surface is dirty.\n");
02764     }
02765     else
02766     {
02767         TRACE("surface is already in texture\n");
02768         return WINED3D_OK;
02769     }
02770 
02771     /* No partial locking for textures yet. */
02772     surface_load_location(surface, flag, NULL);
02773     surface_evict_sysmem(surface);
02774 
02775     return WINED3D_OK;
02776 }
02777 
02778 /* See also float_16_to_32() in wined3d_private.h */
02779 static inline unsigned short float_32_to_16(const float *in)
02780 {
02781     int exp = 0;
02782     float tmp = fabsf(*in);
02783     unsigned int mantissa;
02784     unsigned short ret;
02785 
02786     /* Deal with special numbers */
02787     if (*in == 0.0f)
02788         return 0x0000;
02789     if (isnan(*in))
02790         return 0x7c01;
02791     if (isinf(*in))
02792         return (*in < 0.0f ? 0xfc00 : 0x7c00);
02793 
02794     if (tmp < powf(2, 10))
02795     {
02796         do
02797         {
02798             tmp = tmp * 2.0f;
02799             exp--;
02800         } while (tmp < powf(2, 10));
02801     }
02802     else if (tmp >= powf(2, 11))
02803     {
02804         do
02805         {
02806             tmp /= 2.0f;
02807             exp++;
02808         } while (tmp >= powf(2, 11));
02809     }
02810 
02811     mantissa = (unsigned int)tmp;
02812     if (tmp - mantissa >= 0.5f)
02813         ++mantissa; /* Round to nearest, away from zero. */
02814 
02815     exp += 10;  /* Normalize the mantissa. */
02816     exp += 15;  /* Exponent is encoded with excess 15. */
02817 
02818     if (exp > 30) /* too big */
02819     {
02820         ret = 0x7c00; /* INF */
02821     }
02822     else if (exp <= 0)
02823     {
02824         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
02825         while (exp <= 0)
02826         {
02827             mantissa = mantissa >> 1;
02828             ++exp;
02829         }
02830         ret = mantissa & 0x3ff;
02831     }
02832     else
02833     {
02834         ret = (exp << 10) | (mantissa & 0x3ff);
02835     }
02836 
02837     ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
02838     return ret;
02839 }
02840 
02841 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
02842 {
02843     ULONG refcount;
02844 
02845     TRACE("Surface %p, container %p of type %#x.\n",
02846             surface, surface->container.u.base, surface->container.type);
02847 
02848     switch (surface->container.type)
02849     {
02850         case WINED3D_CONTAINER_TEXTURE:
02851             return wined3d_texture_incref(surface->container.u.texture);
02852 
02853         case WINED3D_CONTAINER_SWAPCHAIN:
02854             return wined3d_swapchain_incref(surface->container.u.swapchain);
02855 
02856         default:
02857             ERR("Unhandled container type %#x.\n", surface->container.type);
02858         case WINED3D_CONTAINER_NONE:
02859             break;
02860     }
02861 
02862     refcount = InterlockedIncrement(&surface->resource.ref);
02863     TRACE("%p increasing refcount to %u.\n", surface, refcount);
02864 
02865     return refcount;
02866 }
02867 
02868 /* Do not call while under the GL lock. */
02869 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
02870 {
02871     ULONG refcount;
02872 
02873     TRACE("Surface %p, container %p of type %#x.\n",
02874             surface, surface->container.u.base, surface->container.type);
02875 
02876     switch (surface->container.type)
02877     {
02878         case WINED3D_CONTAINER_TEXTURE:
02879             return wined3d_texture_decref(surface->container.u.texture);
02880 
02881         case WINED3D_CONTAINER_SWAPCHAIN:
02882             return wined3d_swapchain_decref(surface->container.u.swapchain);
02883 
02884         default:
02885             ERR("Unhandled container type %#x.\n", surface->container.type);
02886         case WINED3D_CONTAINER_NONE:
02887             break;
02888     }
02889 
02890     refcount = InterlockedDecrement(&surface->resource.ref);
02891     TRACE("%p decreasing refcount to %u.\n", surface, refcount);
02892 
02893     if (!refcount)
02894     {
02895         surface_cleanup(surface);
02896         surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
02897 
02898         TRACE("Destroyed surface %p.\n", surface);
02899         HeapFree(GetProcessHeap(), 0, surface);
02900     }
02901 
02902     return refcount;
02903 }
02904 
02905 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
02906 {
02907     return resource_set_priority(&surface->resource, priority);
02908 }
02909 
02910 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
02911 {
02912     return resource_get_priority(&surface->resource);
02913 }
02914 
02915 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
02916 {
02917     TRACE("surface %p.\n", surface);
02918 
02919     if (!surface->resource.device->d3d_initialized)
02920     {
02921         ERR("D3D not initialized.\n");
02922         return;
02923     }
02924 
02925     surface_internal_preload(surface, SRGB_ANY);
02926 }
02927 
02928 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
02929 {
02930     TRACE("surface %p.\n", surface);
02931 
02932     return surface->resource.parent;
02933 }
02934 
02935 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
02936 {
02937     TRACE("surface %p.\n", surface);
02938 
02939     return &surface->resource;
02940 }
02941 
02942 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
02943 {
02944     TRACE("surface %p, flags %#x.\n", surface, flags);
02945 
02946     switch (flags)
02947     {
02948         case WINEDDGBS_CANBLT:
02949         case WINEDDGBS_ISBLTDONE:
02950             return WINED3D_OK;
02951 
02952         default:
02953             return WINED3DERR_INVALIDCALL;
02954     }
02955 }
02956 
02957 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
02958 {
02959     TRACE("surface %p, flags %#x.\n", surface, flags);
02960 
02961     /* XXX: DDERR_INVALIDSURFACETYPE */
02962 
02963     switch (flags)
02964     {
02965         case WINEDDGFS_CANFLIP:
02966         case WINEDDGFS_ISFLIPDONE:
02967             return WINED3D_OK;
02968 
02969         default:
02970             return WINED3DERR_INVALIDCALL;
02971     }
02972 }
02973 
02974 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
02975 {
02976     TRACE("surface %p.\n", surface);
02977 
02978     /* D3D8 and 9 loose full devices, ddraw only surfaces. */
02979     return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
02980 }
02981 
02982 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
02983 {
02984     TRACE("surface %p.\n", surface);
02985 
02986     surface->flags &= ~SFLAG_LOST;
02987     return WINED3D_OK;
02988 }
02989 
02990 HRESULT CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
02991 {
02992     TRACE("surface %p, palette %p.\n", surface, palette);
02993 
02994     if (surface->palette == palette)
02995     {
02996         TRACE("Nop palette change.\n");
02997         return WINED3D_OK;
02998     }
02999 
03000     if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
03001         surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
03002 
03003     surface->palette = palette;
03004 
03005     if (palette)
03006     {
03007         if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
03008             palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
03009 
03010         surface->surface_ops->surface_realize_palette(surface);
03011     }
03012 
03013     return WINED3D_OK;
03014 }
03015 
03016 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
03017         DWORD flags, const struct wined3d_color_key *color_key)
03018 {
03019     TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
03020 
03021     if (flags & WINEDDCKEY_COLORSPACE)
03022     {
03023         FIXME(" colorkey value not supported (%08x) !\n", flags);
03024         return WINED3DERR_INVALIDCALL;
03025     }
03026 
03027     /* Dirtify the surface, but only if a key was changed. */
03028     if (color_key)
03029     {
03030         switch (flags & ~WINEDDCKEY_COLORSPACE)
03031         {
03032             case WINEDDCKEY_DESTBLT:
03033                 surface->dst_blt_color_key = *color_key;
03034                 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
03035                 break;
03036 
03037             case WINEDDCKEY_DESTOVERLAY:
03038                 surface->dst_overlay_color_key = *color_key;
03039                 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
03040                 break;
03041 
03042             case WINEDDCKEY_SRCOVERLAY:
03043                 surface->src_overlay_color_key = *color_key;
03044                 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
03045                 break;
03046 
03047             case WINEDDCKEY_SRCBLT:
03048                 surface->src_blt_color_key = *color_key;
03049                 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
03050                 break;
03051         }
03052     }
03053     else
03054     {
03055         switch (flags & ~WINEDDCKEY_COLORSPACE)
03056         {
03057             case WINEDDCKEY_DESTBLT:
03058                 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
03059                 break;
03060 
03061             case WINEDDCKEY_DESTOVERLAY:
03062                 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
03063                 break;
03064 
03065             case WINEDDCKEY_SRCOVERLAY:
03066                 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
03067                 break;
03068 
03069             case WINEDDCKEY_SRCBLT:
03070                 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
03071                 break;
03072         }
03073     }
03074 
03075     return WINED3D_OK;
03076 }
03077 
03078 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
03079 {
03080     TRACE("surface %p.\n", surface);
03081 
03082     return surface->palette;
03083 }
03084 
03085 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
03086 {
03087     const struct wined3d_format *format = surface->resource.format;
03088     DWORD pitch;
03089 
03090     TRACE("surface %p.\n", surface);
03091 
03092     if (format->flags & WINED3DFMT_FLAG_BLOCKS)
03093     {
03094         /* Since compressed formats are block based, pitch means the amount of
03095          * bytes to the next row of block rather than the next row of pixels. */
03096         UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
03097         pitch = row_block_count * format->block_byte_count;
03098     }
03099     else
03100     {
03101         unsigned char alignment = surface->resource.device->surface_alignment;
03102         pitch = surface->resource.format->byte_count * surface->resource.width;  /* Bytes / row */
03103         pitch = (pitch + alignment - 1) & ~(alignment - 1);
03104     }
03105 
03106     TRACE("Returning %u.\n", pitch);
03107 
03108     return pitch;
03109 }
03110 
03111 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
03112 {
03113     TRACE("surface %p, mem %p.\n", surface, mem);
03114 
03115     if (surface->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
03116     {
03117         WARN("Surface is locked or the DC is in use.\n");
03118         return WINED3DERR_INVALIDCALL;
03119     }
03120 
03121     /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
03122     if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
03123     {
03124         ERR("Not supported on render targets.\n");
03125         return WINED3DERR_INVALIDCALL;
03126     }
03127 
03128     if (mem && mem != surface->resource.allocatedMemory)
03129     {
03130         void *release = NULL;
03131 
03132         /* Do I have to copy the old surface content? */
03133         if (surface->flags & SFLAG_DIBSECTION)
03134         {
03135             DeleteDC(surface->hDC);
03136             DeleteObject(surface->dib.DIBsection);
03137             surface->dib.bitmap_data = NULL;
03138             surface->resource.allocatedMemory = NULL;
03139             surface->hDC = NULL;
03140             surface->flags &= ~SFLAG_DIBSECTION;
03141         }
03142         else if (!(surface->flags & SFLAG_USERPTR))
03143         {
03144             release = surface->resource.heapMemory;
03145             surface->resource.heapMemory = NULL;
03146         }
03147         surface->resource.allocatedMemory = mem;
03148         surface->flags |= SFLAG_USERPTR;
03149 
03150         /* Now the surface memory is most up do date. Invalidate drawable and texture. */
03151         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
03152 
03153         /* For client textures OpenGL has to be notified. */
03154         if (surface->flags & SFLAG_CLIENT)
03155             surface_release_client_storage(surface);
03156 
03157         /* Now free the old memory if any. */
03158         HeapFree(GetProcessHeap(), 0, release);
03159     }
03160     else if (surface->flags & SFLAG_USERPTR)
03161     {
03162         /* HeapMemory should be NULL already. */
03163         if (surface->resource.heapMemory)
03164             ERR("User pointer surface has heap memory allocated.\n");
03165 
03166         if (!mem)
03167         {
03168             surface->resource.allocatedMemory = NULL;
03169             surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
03170 
03171             if (surface->flags & SFLAG_CLIENT)
03172                 surface_release_client_storage(surface);
03173 
03174             surface_prepare_system_memory(surface);
03175         }
03176 
03177         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
03178     }
03179 
03180     return WINED3D_OK;
03181 }
03182 
03183 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
03184 {
03185     LONG w, h;
03186 
03187     TRACE("surface %p, x %d, y %d.\n", surface, x, y);
03188 
03189     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
03190     {
03191         WARN("Not an overlay surface.\n");
03192         return WINEDDERR_NOTAOVERLAYSURFACE;
03193     }
03194 
03195     w = surface->overlay_destrect.right - surface->overlay_destrect.left;
03196     h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
03197     surface->overlay_destrect.left = x;
03198     surface->overlay_destrect.top = y;
03199     surface->overlay_destrect.right = x + w;
03200     surface->overlay_destrect.bottom = y + h;
03201 
03202     surface_draw_overlay(surface);
03203 
03204     return WINED3D_OK;
03205 }
03206 
03207 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
03208 {
03209     TRACE("surface %p, x %p, y %p.\n", surface, x, y);
03210 
03211     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
03212     {
03213         TRACE("Not an overlay surface.\n");
03214         return WINEDDERR_NOTAOVERLAYSURFACE;
03215     }
03216 
03217     if (!surface->overlay_dest)
03218     {
03219         TRACE("Overlay not visible.\n");
03220         *x = 0;
03221         *y = 0;
03222         return WINEDDERR_OVERLAYNOTVISIBLE;
03223     }
03224 
03225     *x = surface->overlay_destrect.left;
03226     *y = surface->overlay_destrect.top;
03227 
03228     TRACE("Returning position %d, %d.\n", *x, *y);
03229 
03230     return WINED3D_OK;
03231 }
03232 
03233 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
03234         DWORD flags, struct wined3d_surface *ref)
03235 {
03236     FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
03237 
03238     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
03239     {
03240         TRACE("Not an overlay surface.\n");
03241         return WINEDDERR_NOTAOVERLAYSURFACE;
03242     }
03243 
03244     return WINED3D_OK;
03245 }
03246 
03247 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
03248         struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
03249 {
03250     TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
03251             surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
03252 
03253     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
03254     {
03255         WARN("Not an overlay surface.\n");
03256         return WINEDDERR_NOTAOVERLAYSURFACE;
03257     }
03258     else if (!dst_surface)
03259     {
03260         WARN("Dest surface is NULL.\n");
03261         return WINED3DERR_INVALIDCALL;
03262     }
03263 
03264     if (src_rect)
03265     {
03266         surface->overlay_srcrect = *src_rect;
03267     }
03268     else
03269     {
03270         surface->overlay_srcrect.left = 0;
03271         surface->overlay_srcrect.top = 0;
03272         surface->overlay_srcrect.right = surface->resource.width;
03273         surface->overlay_srcrect.bottom = surface->resource.height;
03274     }
03275 
03276     if (dst_rect)
03277     {
03278         surface->overlay_destrect = *dst_rect;
03279     }
03280     else
03281     {
03282         surface->overlay_destrect.left = 0;
03283         surface->overlay_destrect.top = 0;
03284         surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
03285         surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
03286     }
03287 
03288     if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
03289     {
03290         surface->overlay_dest = NULL;
03291         list_remove(&surface->overlay_entry);
03292     }
03293 
03294     if (flags & WINEDDOVER_SHOW)
03295     {
03296         if (surface->overlay_dest != dst_surface)
03297         {
03298             surface->overlay_dest = dst_surface;
03299             list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
03300         }
03301     }
03302     else if (flags & WINEDDOVER_HIDE)
03303     {
03304         /* tests show that the rectangles are erased on hide */
03305         surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
03306         surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
03307         surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
03308         surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
03309         surface->overlay_dest = NULL;
03310     }
03311 
03312     surface_draw_overlay(surface);
03313 
03314     return WINED3D_OK;
03315 }
03316 
03317 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
03318         UINT width, UINT height, enum wined3d_format_id format_id,
03319         enum wined3d_multisample_type multisample_type, UINT multisample_quality)
03320 {
03321     struct wined3d_device *device = surface->resource.device;
03322     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
03323     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
03324     UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
03325 
03326     TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
03327             surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
03328 
03329     if (!resource_size)
03330         return WINED3DERR_INVALIDCALL;
03331 
03332     if (device->d3d_initialized)
03333         surface->resource.resource_ops->resource_unload(&surface->resource);
03334 
03335     if (surface->flags & SFLAG_DIBSECTION)
03336     {
03337         DeleteDC(surface->hDC);
03338         DeleteObject(surface->dib.DIBsection);
03339         surface->dib.bitmap_data = NULL;
03340         surface->flags &= ~SFLAG_DIBSECTION;
03341     }
03342 
03343     surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
03344     surface->resource.allocatedMemory = NULL;
03345     HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
03346     surface->resource.heapMemory = NULL;
03347 
03348     surface->resource.width = width;
03349     surface->resource.height = height;
03350     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
03351             || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
03352     {
03353         surface->pow2Width = width;
03354         surface->pow2Height = height;
03355     }
03356     else
03357     {
03358         surface->pow2Width = surface->pow2Height = 1;
03359         while (surface->pow2Width < width)
03360             surface->pow2Width <<= 1;
03361         while (surface->pow2Height < height)
03362             surface->pow2Height <<= 1;
03363     }
03364 
03365     if (surface->pow2Width != width || surface->pow2Height != height)
03366         surface->flags |= SFLAG_NONPOW2;
03367     else
03368         surface->flags &= ~SFLAG_NONPOW2;
03369 
03370     surface->resource.format = format;
03371     surface->resource.multisample_type = multisample_type;
03372     surface->resource.multisample_quality = multisample_quality;
03373     surface->resource.size = resource_size;
03374 
03375     if (!surface_init_sysmem(surface))
03376         return E_OUTOFMEMORY;
03377 
03378     return WINED3D_OK;
03379 }
03380 
03381 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
03382         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
03383 {
03384     unsigned short *dst_s;
03385     const float *src_f;
03386     unsigned int x, y;
03387 
03388     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
03389 
03390     for (y = 0; y < h; ++y)
03391     {
03392         src_f = (const float *)(src + y * pitch_in);
03393         dst_s = (unsigned short *) (dst + y * pitch_out);
03394         for (x = 0; x < w; ++x)
03395         {
03396             dst_s[x] = float_32_to_16(src_f + x);
03397         }
03398     }
03399 }
03400 
03401 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
03402         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
03403 {
03404     static const unsigned char convert_5to8[] =
03405     {
03406         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
03407         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
03408         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
03409         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
03410     };
03411     static const unsigned char convert_6to8[] =
03412     {
03413         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
03414         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
03415         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
03416         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
03417         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
03418         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
03419         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
03420         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
03421     };
03422     unsigned int x, y;
03423 
03424     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
03425 
03426     for (y = 0; y < h; ++y)
03427     {
03428         const WORD *src_line = (const WORD *)(src + y * pitch_in);
03429         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
03430         for (x = 0; x < w; ++x)
03431         {
03432             WORD pixel = src_line[x];
03433             dst_line[x] = 0xff000000
03434                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
03435                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
03436                     | convert_5to8[(pixel & 0x001f)];
03437         }
03438     }
03439 }
03440 
03441 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
03442  * in both cases we're just setting the X / Alpha channel to 0xff. */
03443 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
03444         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
03445 {
03446     unsigned int x, y;
03447 
03448     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
03449 
03450     for (y = 0; y < h; ++y)
03451     {
03452         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
03453         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
03454 
03455         for (x = 0; x < w; ++x)
03456         {
03457             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
03458         }
03459     }
03460 }
03461 
03462 static inline BYTE cliptobyte(int x)
03463 {
03464     return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
03465 }
03466 
03467 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
03468         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
03469 {
03470     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
03471     unsigned int x, y;
03472 
03473     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
03474 
03475     for (y = 0; y < h; ++y)
03476     {
03477         const BYTE *src_line = src + y * pitch_in;
03478         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
03479         for (x = 0; x < w; ++x)
03480         {
03481             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
03482              *     C = Y - 16; D = U - 128; E = V - 128;
03483              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
03484              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
03485              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
03486              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
03487              * U and V are shared between the pixels. */
03488             if (!(x & 1)) /* For every even pixel, read new U and V. */
03489             {
03490                 d = (int) src_line[1] - 128;
03491                 e = (int) src_line[3] - 128;
03492                 r2 = 409 * e + 128;
03493                 g2 = - 100 * d - 208 * e + 128;
03494                 b2 = 516 * d + 128;
03495             }
03496             c2 = 298 * ((int) src_line[0] - 16);
03497             dst_line[x] = 0xff000000
03498                 | cliptobyte((c2 + r2) >> 8) << 16    /* red   */
03499                 | cliptobyte((c2 + g2) >> 8) << 8     /* green */
03500                 | cliptobyte((c2 + b2) >> 8);         /* blue  */
03501                 /* Scale RGB values to 0..255 range,
03502                  * then clip them if still not in range (may be negative),
03503                  * then shift them within DWORD if necessary. */
03504             src_line += 2;
03505         }
03506     }
03507 }
03508 
03509 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
03510         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
03511 {
03512     unsigned int x, y;
03513     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
03514 
03515     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
03516 
03517     for (y = 0; y < h; ++y)
03518     {
03519         const BYTE *src_line = src + y * pitch_in;
03520         WORD *dst_line = (WORD *)(dst + y * pitch_out);
03521         for (x = 0; x < w; ++x)
03522         {
03523             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
03524              *     C = Y - 16; D = U - 128; E = V - 128;
03525              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
03526              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
03527              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
03528              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
03529              * U and V are shared between the pixels. */
03530             if (!(x & 1)) /* For every even pixel, read new U and V. */
03531             {
03532                 d = (int) src_line[1] - 128;
03533                 e = (int) src_line[3] - 128;
03534                 r2 = 409 * e + 128;
03535                 g2 = - 100 * d - 208 * e + 128;
03536                 b2 = 516 * d + 128;
03537             }
03538             c2 = 298 * ((int) src_line[0] - 16);
03539             dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11   /* red   */
03540                 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5            /* green */
03541                 | (cliptobyte((c2 + b2) >> 8) >> 3);                /* blue  */
03542                 /* Scale RGB values to 0..255 range,
03543                  * then clip them if still not in range (may be negative),
03544                  * then shift them within DWORD if necessary. */
03545             src_line += 2;
03546         }
03547     }
03548 }
03549 
03550 struct d3dfmt_convertor_desc
03551 {
03552     enum wined3d_format_id from, to;
03553     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
03554 };
03555 
03556 static const struct d3dfmt_convertor_desc convertors[] =
03557 {
03558     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
03559     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
03560     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
03561     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
03562     {WINED3DFMT_YUY2,           WINED3DFMT_B8G8R8X8_UNORM,  convert_yuy2_x8r8g8b8},
03563     {WINED3DFMT_YUY2,           WINED3DFMT_B5G6R5_UNORM,    convert_yuy2_r5g6b5},
03564 };
03565 
03566 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from,
03567         enum wined3d_format_id to)
03568 {
03569     unsigned int i;
03570 
03571     for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i)
03572     {
03573         if (convertors[i].from == from && convertors[i].to == to)
03574             return &convertors[i];
03575     }
03576 
03577     return NULL;
03578 }
03579 
03580 /*****************************************************************************
03581  * surface_convert_format
03582  *
03583  * Creates a duplicate of a surface in a different format. Is used by Blt to
03584  * blit between surfaces with different formats.
03585  *
03586  * Parameters
03587  *  source: Source surface
03588  *  fmt: Requested destination format
03589  *
03590  *****************************************************************************/
03591 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
03592 {
03593     struct wined3d_mapped_rect src_map, dst_map;
03594     const struct d3dfmt_convertor_desc *conv;
03595     struct wined3d_surface *ret = NULL;
03596     HRESULT hr;
03597 
03598     conv = find_convertor(source->resource.format->id, to_fmt);
03599     if (!conv)
03600     {
03601         FIXME("Cannot find a conversion function from format %s to %s.\n",
03602                 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
03603         return NULL;
03604     }
03605 
03606     wined3d_surface_create(source->resource.device, source->resource.width,
03607             source->resource.height, to_fmt, 0 /* level */, 0 /* usage */, WINED3D_POOL_SCRATCH,
03608             WINED3D_MULTISAMPLE_NONE /* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */,
03609             source->surface_type, WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD,
03610             NULL /* parent */, &wined3d_null_parent_ops, &ret);
03611     if (!ret)
03612     {
03613         ERR("Failed to create a destination surface for conversion.\n");
03614         return NULL;
03615     }
03616 
03617     memset(&src_map, 0, sizeof(src_map));
03618     memset(&dst_map, 0, sizeof(dst_map));
03619 
03620     hr = wined3d_surface_map(source, &src_map, NULL, WINED3DLOCK_READONLY);
03621     if (FAILED(hr))
03622     {
03623         ERR("Failed to lock the source surface.\n");
03624         wined3d_surface_decref(ret);
03625         return NULL;
03626     }
03627     hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3DLOCK_READONLY);
03628     if (FAILED(hr))
03629     {
03630         ERR("Failed to lock the destination surface.\n");
03631         wined3d_surface_unmap(source);
03632         wined3d_surface_decref(ret);
03633         return NULL;
03634     }
03635 
03636     conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
03637             source->resource.width, source->resource.height);
03638 
03639     wined3d_surface_unmap(ret);
03640     wined3d_surface_unmap(source);
03641 
03642     return ret;
03643 }
03644 
03645 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
03646         unsigned int bpp, UINT pitch, DWORD color)
03647 {
03648     BYTE *first;
03649     int x, y;
03650 
03651     /* Do first row */
03652 
03653 #define COLORFILL_ROW(type) \
03654 do { \
03655     type *d = (type *)buf; \
03656     for (x = 0; x < width; ++x) \
03657         d[x] = (type)color; \
03658 } while(0)
03659 
03660     switch (bpp)
03661     {
03662         case 1:
03663             COLORFILL_ROW(BYTE);
03664             break;
03665 
03666         case 2:
03667             COLORFILL_ROW(WORD);
03668             break;
03669 
03670         case 3:
03671         {
03672             BYTE *d = buf;
03673             for (x = 0; x < width; ++x, d += 3)
03674             {
03675                 d[0] = (color      ) & 0xFF;
03676                 d[1] = (color >>  8) & 0xFF;
03677                 d[2] = (color >> 16) & 0xFF;
03678             }
03679             break;
03680         }
03681         case 4:
03682             COLORFILL_ROW(DWORD);
03683             break;
03684 
03685         default:
03686             FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
03687             return WINED3DERR_NOTAVAILABLE;
03688     }
03689 
03690 #undef COLORFILL_ROW
03691 
03692     /* Now copy first row. */
03693     first = buf;
03694     for (y = 1; y < height; ++y)
03695     {
03696         buf += pitch;
03697         memcpy(buf, first, width * bpp);
03698     }
03699 
03700     return WINED3D_OK;
03701 }
03702 
03703 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
03704 {
03705     TRACE("surface %p.\n", surface);
03706 
03707     if (!(surface->flags & SFLAG_LOCKED))
03708     {
03709         WARN("Trying to unmap unmapped surface.\n");
03710         return WINEDDERR_NOTLOCKED;
03711     }
03712     surface->flags &= ~SFLAG_LOCKED;
03713 
03714     surface->surface_ops->surface_unmap(surface);
03715 
03716     return WINED3D_OK;
03717 }
03718 
03719 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
03720         struct wined3d_mapped_rect *mapped_rect, const RECT *rect, DWORD flags)
03721 {
03722     const struct wined3d_format *format = surface->resource.format;
03723 
03724     TRACE("surface %p, mapped_rect %p, rect %s, flags %#x.\n",
03725             surface, mapped_rect, wine_dbgstr_rect(rect), flags);
03726 
03727     if (surface->flags & SFLAG_LOCKED)
03728     {
03729         WARN("Surface is already mapped.\n");
03730         return WINED3DERR_INVALIDCALL;
03731     }
03732     if ((format->flags & WINED3DFMT_FLAG_BLOCKS)
03733             && rect && (rect->left || rect->top
03734             || rect->right != surface->resource.width
03735             || rect->bottom != surface->resource.height))
03736     {
03737         UINT width_mask = format->block_width - 1;
03738         UINT height_mask = format->block_height - 1;
03739 
03740         if ((rect->left & width_mask) || (rect->right & width_mask)
03741                 || (rect->top & height_mask) || (rect->bottom & height_mask))
03742         {
03743             WARN("Map rect %s is misaligned for %ux%u blocks.\n",
03744                     wine_dbgstr_rect(rect), format->block_width, format->block_height);
03745 
03746             if (surface->resource.pool == WINED3D_POOL_DEFAULT)
03747                 return WINED3DERR_INVALIDCALL;
03748         }
03749     }
03750 
03751     surface->flags |= SFLAG_LOCKED;
03752 
03753     if (!(surface->flags & SFLAG_LOCKABLE))
03754         WARN("Trying to lock unlockable surface.\n");
03755 
03756     /* Performance optimization: Count how often a surface is mapped, if it is
03757      * mapped regularly do not throw away the system memory copy. This avoids
03758      * the need to download the surface from OpenGL all the time. The surface
03759      * is still downloaded if the OpenGL texture is changed. */
03760     if (!(surface->flags & SFLAG_DYNLOCK))
03761     {
03762         if (++surface->lockCount > MAXLOCKCOUNT)
03763         {
03764             TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
03765             surface->flags |= SFLAG_DYNLOCK;
03766         }
03767     }
03768 
03769     surface->surface_ops->surface_map(surface, rect, flags);
03770 
03771     if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
03772         mapped_rect->row_pitch = surface->resource.width * format->byte_count;
03773     else
03774         mapped_rect->row_pitch = wined3d_surface_get_pitch(surface);
03775 
03776     if (!rect)
03777     {
03778         mapped_rect->data = surface->resource.allocatedMemory;
03779         surface->lockedRect.left = 0;
03780         surface->lockedRect.top = 0;
03781         surface->lockedRect.right = surface->resource.width;
03782         surface->lockedRect.bottom = surface->resource.height;
03783     }
03784     else
03785     {
03786         if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
03787         {
03788             /* Compressed textures are block based, so calculate the offset of
03789              * the block that contains the top-left pixel of the locked rectangle. */
03790             mapped_rect->data = surface->resource.allocatedMemory
03791                     + ((rect->top / format->block_height) * mapped_rect->row_pitch)
03792                     + ((rect->left / format->block_width) * format->block_byte_count);
03793         }
03794         else
03795         {
03796             mapped_rect->data = surface->resource.allocatedMemory
03797                     + (mapped_rect->row_pitch * rect->top)
03798                     + (rect->left * format->byte_count);
03799         }
03800         surface->lockedRect.left = rect->left;
03801         surface->lockedRect.top = rect->top;
03802         surface->lockedRect.right = rect->right;
03803         surface->lockedRect.bottom = rect->bottom;
03804     }
03805 
03806     TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
03807     TRACE("Returning memory %p, pitch %u.\n", mapped_rect->data, mapped_rect->row_pitch);
03808 
03809     return WINED3D_OK;
03810 }
03811 
03812 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
03813 {
03814     struct wined3d_mapped_rect map;
03815     HRESULT hr;
03816 
03817     TRACE("surface %p, dc %p.\n", surface, dc);
03818 
03819     if (surface->flags & SFLAG_USERPTR)
03820     {
03821         ERR("Not supported on surfaces with application-provided memory.\n");
03822         return WINEDDERR_NODC;
03823     }
03824 
03825     /* Give more detailed info for ddraw. */
03826     if (surface->flags & SFLAG_DCINUSE)
03827         return WINEDDERR_DCALREADYCREATED;
03828 
03829     /* Can't GetDC if the surface is locked. */
03830     if (surface->flags & SFLAG_LOCKED)
03831         return WINED3DERR_INVALIDCALL;
03832 
03833     /* Create a DIB section if there isn't a dc yet. */
03834     if (!surface->hDC)
03835     {
03836         if (surface->flags & SFLAG_CLIENT)
03837         {
03838             surface_load_location(surface, SFLAG_INSYSMEM, NULL);
03839             surface_release_client_storage(surface);
03840         }
03841         hr = surface_create_dib_section(surface);
03842         if (FAILED(hr))
03843             return WINED3DERR_INVALIDCALL;
03844 
03845         /* Use the DIB section from now on if we are not using a PBO. */
03846         if (!(surface->flags & SFLAG_PBO))
03847             surface->resource.allocatedMemory = surface->dib.bitmap_data;
03848     }
03849 
03850     /* Map the surface. */
03851     hr = wined3d_surface_map(surface, &map, NULL, 0);
03852     if (FAILED(hr))
03853     {
03854         ERR("Map failed, hr %#x.\n", hr);
03855         return hr;
03856     }
03857 
03858     /* Sync the DIB with the PBO. This can't be done earlier because Map()
03859      * activates the allocatedMemory. */
03860     if (surface->flags & SFLAG_PBO)
03861         memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
03862 
03863     if (surface->resource.format->id == WINED3DFMT_P8_UINT
03864             || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
03865     {
03866         /* GetDC on palettized formats is unsupported in D3D9, and the method
03867          * is missing in D3D8, so this should only be used for DX <=7
03868          * surfaces (with non-device palettes). */
03869         const PALETTEENTRY *pal = NULL;
03870 
03871         if (surface->palette)
03872         {
03873             pal = surface->palette->palents;
03874         }
03875         else
03876         {
03877             struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
03878             struct wined3d_surface *dds_primary = swapchain->front_buffer;
03879 
03880             if (dds_primary && dds_primary->palette)
03881                 pal = dds_primary->palette->palents;
03882         }
03883 
03884         if (pal)
03885         {
03886             RGBQUAD col[256];
03887             unsigned int i;
03888 
03889             for (i = 0; i < 256; ++i)
03890             {
03891                 col[i].rgbRed = pal[i].peRed;
03892                 col[i].rgbGreen = pal[i].peGreen;
03893                 col[i].rgbBlue = pal[i].peBlue;
03894                 col[i].rgbReserved = 0;
03895             }
03896             SetDIBColorTable(surface->hDC, 0, 256, col);
03897         }
03898     }
03899 
03900     surface->flags |= SFLAG_DCINUSE;
03901 
03902     *dc = surface->hDC;
03903     TRACE("Returning dc %p.\n", *dc);
03904 
03905     return WINED3D_OK;
03906 }
03907 
03908 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
03909 {
03910     TRACE("surface %p, dc %p.\n", surface, dc);
03911 
03912     if (!(surface->flags & SFLAG_DCINUSE))
03913         return WINEDDERR_NODC;
03914 
03915     if (surface->hDC != dc)
03916     {
03917         WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
03918                 dc, surface->hDC);
03919         return WINEDDERR_NODC;
03920     }
03921 
03922     /* Copy the contents of the DIB over to the PBO. */
03923     if ((surface->flags & SFLAG_PBO) && surface->resource.allocatedMemory)
03924         memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
03925 
03926     /* We locked first, so unlock now. */
03927     wined3d_surface_unmap(surface);
03928 
03929     surface->flags &= ~SFLAG_DCINUSE;
03930 
03931     return WINED3D_OK;
03932 }
03933 
03934 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
03935 {
03936     TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
03937 
03938     if (flags)
03939     {
03940         static UINT once;
03941         if (!once++)
03942             FIXME("Ignoring flags %#x.\n", flags);
03943         else
03944             WARN("Ignoring flags %#x.\n", flags);
03945     }
03946 
03947     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
03948     {
03949         ERR("Not supported on swapchain surfaces.\n");
03950         return WINEDDERR_NOTFLIPPABLE;
03951     }
03952 
03953     /* Flipping is only supported on render targets and overlays. */
03954     if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
03955     {
03956         WARN("Tried to flip a non-render target, non-overlay surface.\n");
03957         return WINEDDERR_NOTFLIPPABLE;
03958     }
03959 
03960     flip_surface(surface, override);
03961 
03962     /* Update overlays if they're visible. */
03963     if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
03964         return surface_draw_overlay(surface);
03965 
03966     return WINED3D_OK;
03967 }
03968 
03969 /* Do not call while under the GL lock. */
03970 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
03971 {
03972     struct wined3d_device *device = surface->resource.device;
03973 
03974     TRACE("iface %p, srgb %#x.\n", surface, srgb);
03975 
03976     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
03977     {
03978         struct wined3d_texture *texture = surface->container.u.texture;
03979 
03980         TRACE("Passing to container (%p).\n", texture);
03981         texture->texture_ops->texture_preload(texture, srgb);
03982     }
03983     else
03984     {
03985         struct wined3d_context *context;
03986 
03987         TRACE("(%p) : About to load surface\n", surface);
03988 
03989         /* TODO: Use already acquired context when possible. */
03990         context = context_acquire(device, NULL);
03991 
03992         surface_load(surface, srgb == SRGB_SRGB ? TRUE : FALSE);
03993 
03994         if (surface->resource.pool == WINED3D_POOL_DEFAULT)
03995         {
03996             /* Tell opengl to try and keep this texture in video ram (well mostly) */
03997             GLclampf tmp;
03998             tmp = 0.9f;
03999             ENTER_GL();
04000             glPrioritizeTextures(1, &surface->texture_name, &tmp);
04001             LEAVE_GL();
04002         }
04003 
04004         context_release(context);
04005     }
04006 }
04007 
04008 BOOL surface_init_sysmem(struct wined3d_surface *surface)
04009 {
04010     if (!surface->resource.allocatedMemory)
04011     {
04012         if (!surface->resource.heapMemory)
04013         {
04014             if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
04015                     surface->resource.size + RESOURCE_ALIGNMENT)))
04016             {
04017                 ERR("Failed to allocate memory.\n");
04018                 return FALSE;
04019             }
04020         }
04021         else if (!(surface->flags & SFLAG_CLIENT))
04022         {
04023             ERR("Surface %p has heapMemory %p and flags %#x.\n",
04024                     surface, surface->resource.heapMemory, surface->flags);
04025         }
04026 
04027         surface->resource.allocatedMemory =
04028             (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
04029     }
04030     else
04031     {
04032         memset(surface->resource.allocatedMemory, 0, surface->resource.size);
04033     }
04034 
04035     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
04036 
04037     return TRUE;
04038 }
04039 
04040 /* Read the framebuffer back into the surface */
04041 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
04042 {
04043     struct wined3d_device *device = surface->resource.device;
04044     const struct wined3d_gl_info *gl_info;
04045     struct wined3d_context *context;
04046     BYTE *mem;
04047     GLint fmt;
04048     GLint type;
04049     BYTE *row, *top, *bottom;
04050     int i;
04051     BOOL bpp;
04052     RECT local_rect;
04053     BOOL srcIsUpsideDown;
04054     GLint rowLen = 0;
04055     GLint skipPix = 0;
04056     GLint skipRow = 0;
04057 
04058     context = context_acquire(device, surface);
04059     context_apply_blit_state(context, device);
04060     gl_info = context->gl_info;
04061 
04062     ENTER_GL();
04063 
04064     /* Select the correct read buffer, and give some debug output.
04065      * There is no need to keep track of the current read buffer or reset it, every part of the code
04066      * that reads sets the read buffer as desired.
04067      */
04068     if (surface_is_offscreen(surface))
04069     {
04070         /* Mapping the primary render target which is not on a swapchain.
04071          * Read from the back buffer. */
04072         TRACE("Mapping offscreen render target.\n");
04073         glReadBuffer(device->offscreenBuffer);
04074         srcIsUpsideDown = TRUE;
04075     }
04076     else
04077     {
04078         /* Onscreen surfaces are always part of a swapchain */
04079         GLenum buffer = surface_get_gl_buffer(surface);
04080         TRACE("Mapping %#x buffer.\n", buffer);
04081         glReadBuffer(buffer);
04082         checkGLcall("glReadBuffer");
04083         srcIsUpsideDown = FALSE;
04084     }
04085 
04086     /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
04087     if (!rect)
04088     {
04089         local_rect.left = 0;
04090         local_rect.top = 0;
04091         local_rect.right = surface->resource.width;
04092         local_rect.bottom = surface->resource.height;
04093     }
04094     else
04095     {
04096         local_rect = *rect;
04097     }
04098     /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
04099 
04100     switch (surface->resource.format->id)
04101     {
04102         case WINED3DFMT_P8_UINT:
04103         {
04104             if (primary_render_target_is_p8(device))
04105             {
04106                 /* In case of P8 render targets the index is stored in the alpha component */
04107                 fmt = GL_ALPHA;
04108                 type = GL_UNSIGNED_BYTE;
04109                 mem = dest;
04110                 bpp = surface->resource.format->byte_count;
04111             }
04112             else
04113             {
04114                 /* GL can't return palettized data, so read ARGB pixels into a
04115                  * separate block of memory and convert them into palettized format
04116                  * in software. Slow, but if the app means to use palettized render
04117                  * targets and locks it...
04118                  *
04119                  * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
04120                  * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
04121                  * for the color channels when palettizing the colors.
04122                  */
04123                 fmt = GL_RGB;
04124                 type = GL_UNSIGNED_BYTE;
04125                 pitch *= 3;
04126                 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
04127                 if (!mem)
04128                 {
04129                     ERR("Out of memory\n");
04130                     LEAVE_GL();
04131                     return;
04132                 }
04133                 bpp = surface->resource.format->byte_count * 3;
04134             }
04135         }
04136         break;
04137 
04138         default:
04139             mem = dest;
04140             fmt = surface->resource.format->glFormat;
04141             type = surface->resource.format->glType;
04142             bpp = surface->resource.format->byte_count;
04143     }
04144 
04145     if (surface->flags & SFLAG_PBO)
04146     {
04147         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
04148         checkGLcall("glBindBufferARB");
04149         if (mem)
04150         {
04151             ERR("mem not null for pbo -- unexpected\n");
04152             mem = NULL;
04153         }
04154     }
04155 
04156     /* Save old pixel store pack state */
04157     glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
04158     checkGLcall("glGetIntegerv");
04159     glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
04160     checkGLcall("glGetIntegerv");
04161     glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
04162     checkGLcall("glGetIntegerv");
04163 
04164     /* Setup pixel store pack state -- to glReadPixels into the correct place */
04165     glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
04166     checkGLcall("glPixelStorei");
04167     glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
04168     checkGLcall("glPixelStorei");
04169     glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
04170     checkGLcall("glPixelStorei");
04171 
04172     glReadPixels(local_rect.left, !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
04173             local_rect.right - local_rect.left,
04174             local_rect.bottom - local_rect.top,
04175             fmt, type, mem);
04176     checkGLcall("glReadPixels");
04177 
04178     /* Reset previous pixel store pack state */
04179     glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
04180     checkGLcall("glPixelStorei");
04181     glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
04182     checkGLcall("glPixelStorei");
04183     glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
04184     checkGLcall("glPixelStorei");
04185 
04186     if (surface->flags & SFLAG_PBO)
04187     {
04188         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
04189         checkGLcall("glBindBufferARB");
04190 
04191         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
04192          * to get a pointer to it and perform the flipping in software. This is a lot
04193          * faster than calling glReadPixels for each line. In case we want more speed
04194          * we should rerender it flipped in a FBO and read the data back from the FBO. */
04195         if (!srcIsUpsideDown)
04196         {
04197             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
04198             checkGLcall("glBindBufferARB");
04199 
04200             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
04201             checkGLcall("glMapBufferARB");
04202         }
04203     }
04204 
04205     /* TODO: Merge this with the palettization loop below for P8 targets */
04206     if(!srcIsUpsideDown) {
04207         UINT len, off;
04208         /* glReadPixels returns the image upside down, and there is no way to prevent this.
04209             Flip the lines in software */
04210         len = (local_rect.right - local_rect.left) * bpp;
04211         off = local_rect.left * bpp;
04212 
04213         row = HeapAlloc(GetProcessHeap(), 0, len);
04214         if(!row) {
04215             ERR("Out of memory\n");
04216             if (surface->resource.format->id == WINED3DFMT_P8_UINT)
04217                 HeapFree(GetProcessHeap(), 0, mem);
04218             LEAVE_GL();
04219             return;
04220         }
04221 
04222         top = mem + pitch * local_rect.top;
04223         bottom = mem + pitch * (local_rect.bottom - 1);
04224         for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
04225             memcpy(row, top + off, len);
04226             memcpy(top + off, bottom + off, len);
04227             memcpy(bottom + off, row, len);
04228             top += pitch;
04229             bottom -= pitch;
04230         }
04231         HeapFree(GetProcessHeap(), 0, row);
04232 
04233         /* Unmap the temp PBO buffer */
04234         if (surface->flags & SFLAG_PBO)
04235         {
04236             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
04237             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
04238         }
04239     }
04240 
04241     LEAVE_GL();
04242     context_release(context);
04243 
04244     /* For P8 textures we need to perform an inverse palette lookup. This is
04245      * done by searching for a palette index which matches the RGB value.
04246      * Note this isn't guaranteed to work when there are multiple entries for
04247      * the same color but we have no choice. In case of P8 render targets,
04248      * the index is stored in the alpha component so no conversion is needed. */
04249     if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
04250     {
04251         const PALETTEENTRY *pal = NULL;
04252         DWORD width = pitch / 3;
04253         int x, y, c;
04254 
04255         if (surface->palette)
04256         {
04257             pal = surface->palette->palents;
04258         }
04259         else
04260         {
04261             ERR("Palette is missing, cannot perform inverse palette lookup\n");
04262             HeapFree(GetProcessHeap(), 0, mem);
04263             return;
04264         }
04265 
04266         for(y = local_rect.top; y < local_rect.bottom; y++) {
04267             for(x = local_rect.left; x < local_rect.right; x++) {
04268                 /*                      start              lines            pixels      */
04269                 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
04270                 const BYTE *green = blue  + 1;
04271                 const BYTE *red = green + 1;
04272 
04273                 for(c = 0; c < 256; c++) {
04274                     if(*red   == pal[c].peRed   &&
04275                        *green == pal[c].peGreen &&
04276                        *blue  == pal[c].peBlue)
04277                     {
04278                         *((BYTE *) dest + y * width + x) = c;
04279                         break;
04280                     }
04281                 }
04282             }
04283         }
04284         HeapFree(GetProcessHeap(), 0, mem);
04285     }
04286 }
04287 
04288 /* Read the framebuffer contents into a texture. Note that this function
04289  * doesn't do any kind of flipping. Using this on an onscreen surface will
04290  * result in a flipped D3D texture. */
04291 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
04292 {
04293     struct wined3d_device *device = surface->resource.device;
04294     struct wined3d_context *context;
04295 
04296     context = context_acquire(device, surface);
04297     device_invalidate_state(device, STATE_FRAMEBUFFER);
04298 
04299     surface_prepare_texture(surface, context, srgb);
04300     surface_bind_and_dirtify(surface, context, srgb);
04301 
04302     TRACE("Reading back offscreen render target %p.\n", surface);
04303 
04304     ENTER_GL();
04305 
04306     if (surface_is_offscreen(surface))
04307         glReadBuffer(device->offscreenBuffer);
04308     else
04309         glReadBuffer(surface_get_gl_buffer(surface));
04310     checkGLcall("glReadBuffer");
04311 
04312     glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
04313             0, 0, 0, 0, surface->resource.width, surface->resource.height);
04314     checkGLcall("glCopyTexSubImage2D");
04315 
04316     LEAVE_GL();
04317 
04318     context_release(context);
04319 }
04320 
04321 /* Context activation is done by the caller. */
04322 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
04323         struct wined3d_context *context, BOOL srgb)
04324 {
04325     DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
04326     CONVERT_TYPES convert;
04327     struct wined3d_format format;
04328 
04329     if (surface->flags & alloc_flag) return;
04330 
04331     d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
04332     if (convert != NO_CONVERSION || format.convert) surface->flags |= SFLAG_CONVERTED;
04333     else surface->flags &= ~SFLAG_CONVERTED;
04334 
04335     surface_bind_and_dirtify(surface, context, srgb);
04336     surface_allocate_surface(surface, context->gl_info, &format, srgb);
04337     surface->flags |= alloc_flag;
04338 }
04339 
04340 /* Context activation is done by the caller. */
04341 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
04342 {
04343     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
04344     {
04345         struct wined3d_texture *texture = surface->container.u.texture;
04346         UINT sub_count = texture->level_count * texture->layer_count;
04347         UINT i;
04348 
04349         TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
04350 
04351         for (i = 0; i < sub_count; ++i)
04352         {
04353             struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
04354             surface_prepare_texture_internal(s, context, srgb);
04355         }
04356 
04357         return;
04358     }
04359 
04360     surface_prepare_texture_internal(surface, context, srgb);
04361 }
04362 
04363 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
04364 {
04365     if (multisample)
04366     {
04367         if (surface->rb_multisample)
04368             return;
04369 
04370         gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
04371         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
04372         gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
04373                 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
04374         TRACE("Created multisample rb %u.\n", surface->rb_multisample);
04375     }
04376     else
04377     {
04378         if (surface->rb_resolved)
04379             return;
04380 
04381         gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
04382         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
04383         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
04384                 surface->pow2Width, surface->pow2Height);
04385         TRACE("Created resolved rb %u.\n", surface->rb_resolved);
04386     }
04387 }
04388 
04389 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
04390         const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
04391 {
04392     struct wined3d_device *device = surface->resource.device;
04393     UINT pitch = wined3d_surface_get_pitch(surface);
04394     const struct wined3d_gl_info *gl_info;
04395     struct wined3d_context *context;
04396     RECT local_rect;
04397     UINT w, h;
04398 
04399     surface_get_rect(surface, rect, &local_rect);
04400 
04401     mem += local_rect.top * pitch + local_rect.left * bpp;
04402     w = local_rect.right - local_rect.left;
04403     h = local_rect.bottom - local_rect.top;
04404 
04405     /* Activate the correct context for the render target */
04406     context = context_acquire(device, surface);
04407     context_apply_blit_state(context, device);
04408     gl_info = context->gl_info;
04409 
04410     ENTER_GL();
04411 
04412     if (!surface_is_offscreen(surface))
04413     {
04414         GLenum buffer = surface_get_gl_buffer(surface);
04415         TRACE("Unlocking %#x buffer.\n", buffer);
04416         context_set_draw_buffer(context, buffer);
04417 
04418         surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
04419         glPixelZoom(1.0f, -1.0f);
04420     }
04421     else
04422     {
04423         /* Primary offscreen render target */
04424         TRACE("Offscreen render target.\n");
04425         context_set_draw_buffer(context, device->offscreenBuffer);
04426 
04427         glPixelZoom(1.0f, 1.0f);
04428     }
04429 
04430     glRasterPos3i(local_rect.left, local_rect.top, 1);
04431     checkGLcall("glRasterPos3i");
04432 
04433     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
04434     glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
04435 
04436     if (surface->flags & SFLAG_PBO)
04437     {
04438         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
04439         checkGLcall("glBindBufferARB");
04440     }
04441 
04442     glDrawPixels(w, h, fmt, type, mem);
04443     checkGLcall("glDrawPixels");
04444 
04445     if (surface->flags & SFLAG_PBO)
04446     {
04447         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
04448         checkGLcall("glBindBufferARB");
04449     }
04450 
04451     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
04452     checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
04453 
04454     LEAVE_GL();
04455 
04456     if (wined3d_settings.strict_draw_ordering
04457             || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
04458             && surface->container.u.swapchain->front_buffer == surface))
04459         wglFlush();
04460 
04461     context_release(context);
04462 }
04463 
04464 HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck,
04465         BOOL use_texturing, struct wined3d_format *format, CONVERT_TYPES *convert)
04466 {
04467     BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
04468     const struct wined3d_device *device = surface->resource.device;
04469     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
04470     BOOL blit_supported = FALSE;
04471 
04472     /* Copy the default values from the surface. Below we might perform fixups */
04473     /* TODO: get rid of color keying desc fixups by using e.g. a table. */
04474     *format = *surface->resource.format;
04475     *convert = NO_CONVERSION;
04476 
04477     /* Ok, now look if we have to do any conversion */
04478     switch (surface->resource.format->id)
04479     {
04480         case WINED3DFMT_P8_UINT:
04481             /* Below the call to blit_supported is disabled for Wine 1.2
04482              * because the function isn't operating correctly yet. At the
04483              * moment 8-bit blits are handled in software and if certain GL
04484              * extensions are around, surface conversion is performed at
04485              * upload time. The blit_supported call recognizes it as a
04486              * destination fixup. This type of upload 'fixup' and 8-bit to
04487              * 8-bit blits need to be handled by the blit_shader.
04488              * TODO: get rid of this #if 0. */
04489 #if 0
04490             blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
04491                     &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
04492                     &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
04493 #endif
04494             blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
04495 
04496             /* Use conversion when the blit_shader backend supports it. It only supports this in case of
04497              * texturing. Further also use conversion in case of color keying.
04498              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
04499              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
04500              * conflicts with this.
04501              */
04502             if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
04503                     || colorkey_active || !use_texturing)
04504             {
04505                 format->glFormat = GL_RGBA;
04506                 format->glInternal = GL_RGBA;
04507                 format->glType = GL_UNSIGNED_BYTE;
04508                 format->conv_byte_count = 4;
04509                 if (colorkey_active)
04510                     *convert = CONVERT_PALETTED_CK;
04511                 else
04512                     *convert = CONVERT_PALETTED;
04513             }
04514             break;
04515 
04516         case WINED3DFMT_B2G3R3_UNORM:
04517             /* **********************
04518                 GL_UNSIGNED_BYTE_3_3_2
04519                 ********************** */
04520             if (colorkey_active) {
04521                 /* This texture format will never be used.. So do not care about color keying
04522                     up until the point in time it will be needed :-) */
04523                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
04524             }
04525             break;
04526 
04527         case WINED3DFMT_B5G6R5_UNORM:
04528             if (colorkey_active)
04529             {
04530                 *convert = CONVERT_CK_565;
04531                 format->glFormat = GL_RGBA;
04532                 format->glInternal = GL_RGB5_A1;
04533                 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
04534                 format->conv_byte_count = 2;
04535             }
04536             break;
04537 
04538         case WINED3DFMT_B5G5R5X1_UNORM:
04539             if (colorkey_active)
04540             {
04541                 *convert = CONVERT_CK_5551;
04542                 format->glFormat = GL_BGRA;
04543                 format->glInternal = GL_RGB5_A1;
04544                 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
04545                 format->conv_byte_count = 2;
04546             }
04547             break;
04548 
04549         case WINED3DFMT_B8G8R8_UNORM:
04550             if (colorkey_active)
04551             {
04552                 *convert = CONVERT_CK_RGB24;
04553                 format->glFormat = GL_RGBA;
04554                 format->glInternal = GL_RGBA8;
04555                 format->glType = GL_UNSIGNED_INT_8_8_8_8;
04556                 format->conv_byte_count = 4;
04557             }
04558             break;
04559 
04560         case WINED3DFMT_B8G8R8X8_UNORM:
04561             if (colorkey_active)
04562             {
04563                 *convert = CONVERT_RGB32_888;
04564                 format->glFormat = GL_RGBA;
04565                 format->glInternal = GL_RGBA8;
04566                 format->glType = GL_UNSIGNED_INT_8_8_8_8;
04567                 format->conv_byte_count = 4;
04568             }
04569             break;
04570 
04571         default:
04572             break;
04573     }
04574 
04575     if (*convert != NO_CONVERSION)
04576     {
04577         format->rtInternal = format->glInternal;
04578         format->glGammaInternal = format->glInternal;
04579     }
04580 
04581     return WINED3D_OK;
04582 }
04583 
04584 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
04585 {
04586     /* FIXME: Is this really how color keys are supposed to work? I think it
04587      * makes more sense to compare the individual channels. */
04588     return color >= color_key->color_space_low_value
04589             && color <= color_key->color_space_high_value;
04590 }
04591 
04592 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
04593 {
04594     const struct wined3d_device *device = surface->resource.device;
04595     const struct wined3d_palette *pal = surface->palette;
04596     BOOL index_in_alpha = FALSE;
04597     unsigned int i;
04598 
04599     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
04600      * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
04601      * is slow. Further RGB->P8 conversion is not possible because palettes can have
04602      * duplicate entries. Store the color key in the unused alpha component to speed the
04603      * download up and to make conversion unneeded. */
04604     index_in_alpha = primary_render_target_is_p8(device);
04605 
04606     if (!pal)
04607     {
04608         ERR("This code should never get entered for DirectDraw!, expect problems\n");
04609         if (index_in_alpha)
04610         {
04611             /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
04612              * there's no palette at this time. */
04613             for (i = 0; i < 256; i++) table[i][3] = i;
04614         }
04615     }
04616     else
04617     {
04618         TRACE("Using surface palette %p\n", pal);
04619         /* Get the surface's palette */
04620         for (i = 0; i < 256; ++i)
04621         {
04622             table[i][0] = pal->palents[i].peRed;
04623             table[i][1] = pal->palents[i].peGreen;
04624             table[i][2] = pal->palents[i].peBlue;
04625 
04626             /* When index_in_alpha is set the palette index is stored in the
04627              * alpha component. In case of a readback we can then read
04628              * GL_ALPHA. Color keying is handled in BltOverride using a
04629              * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
04630              * color key itself is passed to glAlphaFunc in other cases the
04631              * alpha component of pixels that should be masked away is set to 0. */
04632             if (index_in_alpha)
04633                 table[i][3] = i;
04634             else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
04635                 table[i][3] = 0x00;
04636             else if (pal->flags & WINEDDPCAPS_ALPHA)
04637                 table[i][3] = pal->palents[i].peFlags;
04638             else
04639                 table[i][3] = 0xFF;
04640         }
04641     }
04642 }
04643 
04644 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
04645         UINT height, UINT outpitch, CONVERT_TYPES convert, struct wined3d_surface *surface)
04646 {
04647     const BYTE *source;
04648     BYTE *dest;
04649     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surface);
04650 
04651     switch (convert) {
04652         case NO_CONVERSION:
04653         {
04654             memcpy(dst, src, pitch * height);
04655             break;
04656         }
04657         case CONVERT_PALETTED:
04658         case CONVERT_PALETTED_CK:
04659         {
04660             BYTE table[256][4];
04661             unsigned int x, y;
04662 
04663             d3dfmt_p8_init_palette(surface, table, (convert == CONVERT_PALETTED_CK));
04664 
04665             for (y = 0; y < height; y++)
04666             {
04667                 source = src + pitch * y;
04668                 dest = dst + outpitch * y;
04669                 /* This is an 1 bpp format, using the width here is fine */
04670                 for (x = 0; x < width; x++) {
04671                     BYTE color = *source++;
04672                     *dest++ = table[color][0];
04673                     *dest++ = table[color][1];
04674                     *dest++ = table[color][2];
04675                     *dest++ = table[color][3];
04676                 }
04677             }
04678         }
04679         break;
04680 
04681         case CONVERT_CK_565:
04682         {
04683             /* Converting the 565 format in 5551 packed to emulate color-keying.
04684 
04685               Note : in all these conversion, it would be best to average the averaging
04686                       pixels to get the color of the pixel that will be color-keyed to
04687                       prevent 'color bleeding'. This will be done later on if ever it is
04688                       too visible.
04689 
04690               Note2: Nvidia documents say that their driver does not support alpha + color keying
04691                      on the same surface and disables color keying in such a case
04692             */
04693             unsigned int x, y;
04694             const WORD *Source;
04695             WORD *Dest;
04696 
04697             TRACE("Color keyed 565\n");
04698 
04699             for (y = 0; y < height; y++) {
04700                 Source = (const WORD *)(src + y * pitch);
04701                 Dest = (WORD *) (dst + y * outpitch);
04702                 for (x = 0; x < width; x++ ) {
04703                     WORD color = *Source++;
04704                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
04705                     if (!color_in_range(&surface->src_blt_color_key, color))
04706                         *Dest |= 0x0001;
04707                     Dest++;
04708                 }
04709             }
04710         }
04711         break;
04712 
04713         case CONVERT_CK_5551:
04714         {
04715             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
04716             unsigned int x, y;
04717             const WORD *Source;
04718             WORD *Dest;
04719             TRACE("Color keyed 5551\n");
04720             for (y = 0; y < height; y++) {
04721                 Source = (const WORD *)(src + y * pitch);
04722                 Dest = (WORD *) (dst + y * outpitch);
04723                 for (x = 0; x < width; x++ ) {
04724                     WORD color = *Source++;
04725                     *Dest = color;
04726                     if (!color_in_range(&surface->src_blt_color_key, color))
04727                         *Dest |= (1 << 15);
04728                     else
04729                         *Dest &= ~(1 << 15);
04730                     Dest++;
04731                 }
04732             }
04733         }
04734         break;
04735 
04736         case CONVERT_CK_RGB24:
04737         {
04738             /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
04739             unsigned int x, y;
04740             for (y = 0; y < height; y++)
04741             {
04742                 source = src + pitch * y;
04743                 dest = dst + outpitch * y;
04744                 for (x = 0; x < width; x++) {
04745                     DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
04746                     DWORD dstcolor = color << 8;
04747                     if (!color_in_range(&surface->src_blt_color_key, color))
04748                         dstcolor |= 0xff;
04749                     *(DWORD*)dest = dstcolor;
04750                     source += 3;
04751                     dest += 4;
04752                 }
04753             }
04754         }
04755         break;
04756 
04757         case CONVERT_RGB32_888:
04758         {
04759             /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
04760             unsigned int x, y;
04761             for (y = 0; y < height; y++)
04762             {
04763                 source = src + pitch * y;
04764                 dest = dst + outpitch * y;
04765                 for (x = 0; x < width; x++) {
04766                     DWORD color = 0xffffff & *(const DWORD*)source;
04767                     DWORD dstcolor = color << 8;
04768                     if (!color_in_range(&surface->src_blt_color_key, color))
04769                         dstcolor |= 0xff;
04770                     *(DWORD*)dest = dstcolor;
04771                     source += 4;
04772                     dest += 4;
04773                 }
04774             }
04775         }
04776         break;
04777 
04778         default:
04779             ERR("Unsupported conversion type %#x.\n", convert);
04780     }
04781     return WINED3D_OK;
04782 }
04783 
04784 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
04785 {
04786     /* Flip the surface contents */
04787     /* Flip the DC */
04788     {
04789         HDC tmp;
04790         tmp = front->hDC;
04791         front->hDC = back->hDC;
04792         back->hDC = tmp;
04793     }
04794 
04795     /* Flip the DIBsection */
04796     {
04797         HBITMAP tmp = front->dib.DIBsection;
04798         front->dib.DIBsection = back->dib.DIBsection;
04799         back->dib.DIBsection = tmp;
04800     }
04801 
04802     /* Flip the surface data */
04803     {
04804         void* tmp;
04805 
04806         tmp = front->dib.bitmap_data;
04807         front->dib.bitmap_data = back->dib.bitmap_data;
04808         back->dib.bitmap_data = tmp;
04809 
04810         tmp = front->resource.allocatedMemory;
04811         front->resource.allocatedMemory = back->resource.allocatedMemory;
04812         back->resource.allocatedMemory = tmp;
04813 
04814         tmp = front->resource.heapMemory;
04815         front->resource.heapMemory = back->resource.heapMemory;
04816         back->resource.heapMemory = tmp;
04817     }
04818 
04819     /* Flip the PBO */
04820     {
04821         GLuint tmp_pbo = front->pbo;
04822         front->pbo = back->pbo;
04823         back->pbo = tmp_pbo;
04824     }
04825 
04826     /* Flip the opengl texture */
04827     {
04828         GLuint tmp;
04829 
04830         tmp = back->texture_name;
04831         back->texture_name = front->texture_name;
04832         front->texture_name = tmp;
04833 
04834         tmp = back->texture_name_srgb;
04835         back->texture_name_srgb = front->texture_name_srgb;
04836         front->texture_name_srgb = tmp;
04837 
04838         tmp = back->rb_multisample;
04839         back->rb_multisample = front->rb_multisample;
04840         front->rb_multisample = tmp;
04841 
04842         tmp = back->rb_resolved;
04843         back->rb_resolved = front->rb_resolved;
04844         front->rb_resolved = tmp;
04845 
04846         resource_unload(&back->resource);
04847         resource_unload(&front->resource);
04848     }
04849 
04850     {
04851         DWORD tmp_flags = back->flags;
04852         back->flags = front->flags;
04853         front->flags = tmp_flags;
04854     }
04855 }
04856 
04857 /* Does a direct frame buffer -> texture copy. Stretching is done with single
04858  * pixel copy calls. */
04859 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
04860         const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
04861 {
04862     struct wined3d_device *device = dst_surface->resource.device;
04863     float xrel, yrel;
04864     UINT row;
04865     struct wined3d_context *context;
04866     BOOL upsidedown = FALSE;
04867     RECT dst_rect = *dst_rect_in;
04868 
04869     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
04870      * glCopyTexSubImage is a bit picky about the parameters we pass to it
04871      */
04872     if(dst_rect.top > dst_rect.bottom) {
04873         UINT tmp = dst_rect.bottom;
04874         dst_rect.bottom = dst_rect.top;
04875         dst_rect.top = tmp;
04876         upsidedown = TRUE;
04877     }
04878 
04879     context = context_acquire(device, src_surface);
04880     context_apply_blit_state(context, device);
04881     surface_internal_preload(dst_surface, SRGB_RGB);
04882     ENTER_GL();
04883 
04884     /* Bind the target texture */
04885     context_bind_texture(context, dst_surface->texture_target, dst_surface->texture_name);
04886     if (surface_is_offscreen(src_surface))
04887     {
04888         TRACE("Reading from an offscreen target\n");
04889         upsidedown = !upsidedown;
04890         glReadBuffer(device->offscreenBuffer);
04891     }
04892     else
04893     {
04894         glReadBuffer(surface_get_gl_buffer(src_surface));
04895     }
04896     checkGLcall("glReadBuffer");
04897 
04898     xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
04899     yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
04900 
04901     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
04902     {
04903         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
04904 
04905         if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
04906             ERR("Texture filtering not supported in direct blit.\n");
04907     }
04908     else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
04909             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
04910     {
04911         ERR("Texture filtering not supported in direct blit\n");
04912     }
04913 
04914     if (upsidedown
04915             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
04916             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
04917     {
04918         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
04919 
04920         glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
04921                 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
04922                 src_rect->left, src_surface->resource.height - src_rect->bottom,
04923                 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
04924     }
04925     else
04926     {
04927         UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
04928         /* I have to process this row by row to swap the image,
04929          * otherwise it would be upside down, so stretching in y direction
04930          * doesn't cost extra time
04931          *
04932          * However, stretching in x direction can be avoided if not necessary
04933          */
04934         for(row = dst_rect.top; row < dst_rect.bottom; row++) {
04935             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
04936             {
04937                 /* Well, that stuff works, but it's very slow.
04938                  * find a better way instead
04939                  */
04940                 UINT col;
04941 
04942                 for (col = dst_rect.left; col < dst_rect.right; ++col)
04943                 {
04944                     glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
04945                             dst_rect.left + col /* x offset */, row /* y offset */,
04946                             src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
04947                 }
04948             }
04949             else
04950             {
04951                 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
04952                         dst_rect.left /* x offset */, row /* y offset */,
04953                         src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
04954             }
04955         }
04956     }
04957     checkGLcall("glCopyTexSubImage2D");
04958 
04959     LEAVE_GL();
04960     context_release(context);
04961 
04962     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
04963      * path is never entered
04964      */
04965     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
04966 }
04967 
04968 /* Uses the hardware to stretch and flip the image */
04969 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
04970         const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
04971 {
04972     struct wined3d_device *device = dst_surface->resource.device;
04973     struct wined3d_swapchain *src_swapchain = NULL;
04974     GLuint src, backup = 0;
04975     float left, right, top, bottom; /* Texture coordinates */
04976     UINT fbwidth = src_surface->resource.width;
04977     UINT fbheight = src_surface->resource.height;
04978     struct wined3d_context *context;
04979     GLenum drawBuffer = GL_BACK;
04980     GLenum texture_target;
04981     BOOL noBackBufferBackup;
04982     BOOL src_offscreen;
04983     BOOL upsidedown = FALSE;
04984     RECT dst_rect = *dst_rect_in;
04985 
04986     TRACE("Using hwstretch blit\n");
04987     /* Activate the Proper context for reading from the source surface, set it up for blitting */
04988     context = context_acquire(device, src_surface);
04989     context_apply_blit_state(context, device);
04990     surface_internal_preload(dst_surface, SRGB_RGB);
04991 
04992     src_offscreen = surface_is_offscreen(src_surface);
04993     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
04994     if (!noBackBufferBackup && !src_surface->texture_name)
04995     {
04996         /* Get it a description */
04997         surface_internal_preload(src_surface, SRGB_RGB);
04998     }
04999     ENTER_GL();
05000 
05001     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
05002      * This way we don't have to wait for the 2nd readback to finish to leave this function.
05003      */
05004     if (context->aux_buffers >= 2)
05005     {
05006         /* Got more than one aux buffer? Use the 2nd aux buffer */
05007         drawBuffer = GL_AUX1;
05008     }
05009     else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
05010     {
05011         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
05012         drawBuffer = GL_AUX0;
05013     }
05014 
05015     if(noBackBufferBackup) {
05016         glGenTextures(1, &backup);
05017         checkGLcall("glGenTextures");
05018         context_bind_texture(context, GL_TEXTURE_2D, backup);
05019         texture_target = GL_TEXTURE_2D;
05020     } else {
05021         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
05022          * we are reading from the back buffer, the backup can be used as source texture
05023          */
05024         texture_target = src_surface->texture_target;
05025         context_bind_texture(context, texture_target, src_surface->texture_name);
05026         glEnable(texture_target);
05027         checkGLcall("glEnable(texture_target)");
05028 
05029         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
05030         src_surface->flags &= ~SFLAG_INTEXTURE;
05031     }
05032 
05033     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
05034      * glCopyTexSubImage is a bit picky about the parameters we pass to it
05035      */
05036     if(dst_rect.top > dst_rect.bottom) {
05037         UINT tmp = dst_rect.bottom;
05038         dst_rect.bottom = dst_rect.top;
05039         dst_rect.top = tmp;
05040         upsidedown = TRUE;
05041     }
05042 
05043     if (src_offscreen)
05044     {
05045         TRACE("Reading from an offscreen target\n");
05046         upsidedown = !upsidedown;
05047         glReadBuffer(device->offscreenBuffer);
05048     }
05049     else
05050     {
05051         glReadBuffer(surface_get_gl_buffer(src_surface));
05052     }
05053 
05054     /* TODO: Only back up the part that will be overwritten */
05055     glCopyTexSubImage2D(texture_target, 0,
05056                         0, 0 /* read offsets */,
05057                         0, 0,
05058                         fbwidth,
05059                         fbheight);
05060 
05061     checkGLcall("glCopyTexSubImage2D");
05062 
05063     /* No issue with overriding these - the sampler is dirty due to blit usage */
05064     glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
05065             wined3d_gl_mag_filter(magLookup, filter));
05066     checkGLcall("glTexParameteri");
05067     glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
05068             wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
05069     checkGLcall("glTexParameteri");
05070 
05071     if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
05072         src_swapchain = src_surface->container.u.swapchain;
05073     if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
05074     {
05075         src = backup ? backup : src_surface->texture_name;
05076     }
05077     else
05078     {
05079         glReadBuffer(GL_FRONT);
05080         checkGLcall("glReadBuffer(GL_FRONT)");
05081 
05082         glGenTextures(1, &src);
05083         checkGLcall("glGenTextures(1, &src)");
05084         context_bind_texture(context, GL_TEXTURE_2D, src);
05085 
05086         /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
05087          * out for power of 2 sizes
05088          */
05089         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
05090                 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
05091         checkGLcall("glTexImage2D");
05092         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
05093                             0, 0 /* read offsets */,
05094                             0, 0,
05095                             fbwidth,
05096                             fbheight);
05097 
05098         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
05099         checkGLcall("glTexParameteri");
05100         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
05101         checkGLcall("glTexParameteri");
05102 
05103         glReadBuffer(GL_BACK);
05104         checkGLcall("glReadBuffer(GL_BACK)");
05105 
05106         if(texture_target != GL_TEXTURE_2D) {
05107             glDisable(texture_target);
05108             glEnable(GL_TEXTURE_2D);
05109             texture_target = GL_TEXTURE_2D;
05110         }
05111     }
05112     checkGLcall("glEnd and previous");
05113 
05114     left = src_rect->left;
05115     right = src_rect->right;
05116 
05117     if (!upsidedown)
05118     {
05119         top = src_surface->resource.height - src_rect->top;
05120         bottom = src_surface->resource.height - src_rect->bottom;
05121     }
05122     else
05123     {
05124         top = src_surface->resource.height - src_rect->bottom;
05125         bottom = src_surface->resource.height - src_rect->top;
05126     }
05127 
05128     if (src_surface->flags & SFLAG_NORMCOORD)
05129     {
05130         left /= src_surface->pow2Width;
05131         right /= src_surface->pow2Width;
05132         top /= src_surface->pow2Height;
05133         bottom /= src_surface->pow2Height;
05134     }
05135 
05136     /* draw the source texture stretched and upside down. The correct surface is bound already */
05137     glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
05138     glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
05139 
05140     context_set_draw_buffer(context, drawBuffer);
05141     glReadBuffer(drawBuffer);
05142 
05143     glBegin(GL_QUADS);
05144         /* bottom left */
05145         glTexCoord2f(left, bottom);
05146         glVertex2i(0, 0);
05147 
05148         /* top left */
05149         glTexCoord2f(left, top);
05150         glVertex2i(0, dst_rect.bottom - dst_rect.top);
05151 
05152         /* top right */
05153         glTexCoord2f(right, top);
05154         glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
05155 
05156         /* bottom right */
05157         glTexCoord2f(right, bottom);
05158         glVertex2i(dst_rect.right - dst_rect.left, 0);
05159     glEnd();
05160     checkGLcall("glEnd and previous");
05161 
05162     if (texture_target != dst_surface->texture_target)
05163     {
05164         glDisable(texture_target);
05165         glEnable(dst_surface->texture_target);
05166         texture_target = dst_surface->texture_target;
05167     }
05168 
05169     /* Now read the stretched and upside down image into the destination texture */
05170     context_bind_texture(context, texture_target, dst_surface->texture_name);
05171     glCopyTexSubImage2D(texture_target,
05172                         0,
05173                         dst_rect.left, dst_rect.top, /* xoffset, yoffset */
05174                         0, 0, /* We blitted the image to the origin */
05175                         dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
05176     checkGLcall("glCopyTexSubImage2D");
05177 
05178     if(drawBuffer == GL_BACK) {
05179         /* Write the back buffer backup back */
05180         if(backup) {
05181             if(texture_target != GL_TEXTURE_2D) {
05182                 glDisable(texture_target);
05183                 glEnable(GL_TEXTURE_2D);
05184                 texture_target = GL_TEXTURE_2D;
05185             }
05186             context_bind_texture(context, GL_TEXTURE_2D, backup);
05187         }
05188         else
05189         {
05190             if (texture_target != src_surface->texture_target)
05191             {
05192                 glDisable(texture_target);
05193                 glEnable(src_surface->texture_target);
05194                 texture_target = src_surface->texture_target;
05195             }
05196             context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
05197         }
05198 
05199         glBegin(GL_QUADS);
05200             /* top left */
05201             glTexCoord2f(0.0f, 0.0f);
05202             glVertex2i(0, fbheight);
05203 
05204             /* bottom left */
05205             glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
05206             glVertex2i(0, 0);
05207 
05208             /* bottom right */
05209             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
05210                     (float)fbheight / (float)src_surface->pow2Height);
05211             glVertex2i(fbwidth, 0);
05212 
05213             /* top right */
05214             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
05215             glVertex2i(fbwidth, fbheight);
05216         glEnd();
05217     }
05218     glDisable(texture_target);
05219     checkGLcall("glDisable(texture_target)");
05220 
05221     /* Cleanup */
05222     if (src != src_surface->texture_name && src != backup)
05223     {
05224         glDeleteTextures(1, &src);
05225         checkGLcall("glDeleteTextures(1, &src)");
05226     }
05227     if(backup) {
05228         glDeleteTextures(1, &backup);
05229         checkGLcall("glDeleteTextures(1, &backup)");
05230     }
05231 
05232     LEAVE_GL();
05233 
05234     if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
05235 
05236     context_release(context);
05237 
05238     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
05239      * path is never entered
05240      */
05241     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
05242 }
05243 
05244 /* Front buffer coordinates are always full screen coordinates, but our GL
05245  * drawable is limited to the window's client area. The sysmem and texture
05246  * copies do have the full screen size. Note that GL has a bottom-left
05247  * origin, while D3D has a top-left origin. */
05248 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
05249 {
05250     UINT drawable_height;
05251 
05252     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
05253             && surface == surface->container.u.swapchain->front_buffer)
05254     {
05255         POINT offset = {0, 0};
05256         RECT windowsize;
05257 
05258         ScreenToClient(window, &offset);
05259         OffsetRect(rect, offset.x, offset.y);
05260 
05261         GetClientRect(window, &windowsize);
05262         drawable_height = windowsize.bottom - windowsize.top;
05263     }
05264     else
05265     {
05266         drawable_height = surface->resource.height;
05267     }
05268 
05269     rect->top = drawable_height - rect->top;
05270     rect->bottom = drawable_height - rect->bottom;
05271 }
05272 
05273 static void surface_blt_to_drawable(const struct wined3d_device *device,
05274         enum wined3d_texture_filter_type filter, BOOL color_key,
05275         struct wined3d_surface *src_surface, const RECT *src_rect_in,
05276         struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
05277 {
05278     struct wined3d_context *context;
05279     RECT src_rect, dst_rect;
05280 
05281     src_rect = *src_rect_in;
05282     dst_rect = *dst_rect_in;
05283 
05284     /* Make sure the surface is up-to-date. This should probably use
05285      * surface_load_location() and worry about the destination surface too,
05286      * unless we're overwriting it completely. */
05287     surface_internal_preload(src_surface, SRGB_RGB);
05288 
05289     /* Activate the destination context, set it up for blitting */
05290     context = context_acquire(device, dst_surface);
05291     context_apply_blit_state(context, device);
05292 
05293     if (!surface_is_offscreen(dst_surface))
05294         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
05295 
05296     device->blitter->set_shader(device->blit_priv, context, src_surface);
05297 
05298     ENTER_GL();
05299 
05300     if (color_key)
05301     {
05302         glEnable(GL_ALPHA_TEST);
05303         checkGLcall("glEnable(GL_ALPHA_TEST)");
05304 
05305         /* When the primary render target uses P8, the alpha component
05306          * contains the palette index. Which means that the colorkey is one of
05307          * the palette entries. In other cases pixels that should be masked
05308          * away have alpha set to 0. */
05309         if (primary_render_target_is_p8(device))
05310             glAlphaFunc(GL_NOTEQUAL, (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
05311         else
05312             glAlphaFunc(GL_NOTEQUAL, 0.0f);
05313         checkGLcall("glAlphaFunc");
05314     }
05315     else
05316     {
05317         glDisable(GL_ALPHA_TEST);
05318         checkGLcall("glDisable(GL_ALPHA_TEST)");
05319     }
05320 
05321     draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
05322 
05323     if (color_key)
05324     {
05325         glDisable(GL_ALPHA_TEST);
05326         checkGLcall("glDisable(GL_ALPHA_TEST)");
05327     }
05328 
05329     LEAVE_GL();
05330 
05331     /* Leave the opengl state valid for blitting */
05332     device->blitter->unset_shader(context->gl_info);
05333 
05334     if (wined3d_settings.strict_draw_ordering
05335             || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
05336             && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
05337         wglFlush(); /* Flush to ensure ordering across contexts. */
05338 
05339     context_release(context);
05340 }
05341 
05342 /* Do not call while under the GL lock. */
05343 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
05344 {
05345     struct wined3d_device *device = s->resource.device;
05346     const struct blit_shader *blitter;
05347 
05348     blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
05349             NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
05350     if (!blitter)
05351     {
05352         FIXME("No blitter is capable of performing the requested color fill operation.\n");
05353         return WINED3DERR_INVALIDCALL;
05354     }
05355 
05356     return blitter->color_fill(device, s, rect, color);
05357 }
05358 
05359 /* Do not call while under the GL lock. */
05360 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
05361         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
05362         enum wined3d_texture_filter_type filter)
05363 {
05364     struct wined3d_device *device = dst_surface->resource.device;
05365     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
05366     struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
05367 
05368     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
05369             dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
05370             flags, DDBltFx, debug_d3dtexturefiltertype(filter));
05371 
05372     /* Get the swapchain. One of the surfaces has to be a primary surface */
05373     if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
05374     {
05375         WARN("Destination is in sysmem, rejecting gl blt\n");
05376         return WINED3DERR_INVALIDCALL;
05377     }
05378 
05379     if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
05380         dstSwapchain = dst_surface->container.u.swapchain;
05381 
05382     if (src_surface)
05383     {
05384         if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
05385         {
05386             WARN("Src is in sysmem, rejecting gl blt\n");
05387             return WINED3DERR_INVALIDCALL;
05388         }
05389 
05390         if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
05391             srcSwapchain = src_surface->container.u.swapchain;
05392     }
05393 
05394     /* Early sort out of cases where no render target is used */
05395     if (!dstSwapchain && !srcSwapchain
05396             && src_surface != device->fb.render_targets[0]
05397             && dst_surface != device->fb.render_targets[0])
05398     {
05399         TRACE("No surface is render target, not using hardware blit.\n");
05400         return WINED3DERR_INVALIDCALL;
05401     }
05402 
05403     /* No destination color keying supported */
05404     if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
05405     {
05406         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
05407         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
05408         return WINED3DERR_INVALIDCALL;
05409     }
05410 
05411     if (dstSwapchain && dstSwapchain == srcSwapchain)
05412     {
05413         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
05414         return WINED3DERR_INVALIDCALL;
05415     }
05416 
05417     if (dstSwapchain && srcSwapchain)
05418     {
05419         FIXME("Implement hardware blit between two different swapchains\n");
05420         return WINED3DERR_INVALIDCALL;
05421     }
05422 
05423     if (dstSwapchain)
05424     {
05425         /* Handled with regular texture -> swapchain blit */
05426         if (src_surface == device->fb.render_targets[0])
05427             TRACE("Blit from active render target to a swapchain\n");
05428     }
05429     else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
05430     {
05431         FIXME("Implement blit from a swapchain to the active render target\n");
05432         return WINED3DERR_INVALIDCALL;
05433     }
05434 
05435     if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
05436     {
05437         /* Blit from render target to texture */
05438         BOOL stretchx;
05439 
05440         /* P8 read back is not implemented */
05441         if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
05442                 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
05443         {
05444             TRACE("P8 read back not supported by frame buffer to texture blit\n");
05445             return WINED3DERR_INVALIDCALL;
05446         }
05447 
05448         if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
05449         {
05450             TRACE("Color keying not supported by frame buffer to texture blit\n");
05451             return WINED3DERR_INVALIDCALL;
05452             /* Destination color key is checked above */
05453         }
05454 
05455         if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
05456             stretchx = TRUE;
05457         else
05458             stretchx = FALSE;
05459 
05460         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
05461          * flip the image nor scale it.
05462          *
05463          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
05464          * -> If the app wants a image width an unscaled width, copy it line per line
05465          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
05466          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
05467          *    back buffer. This is slower than reading line per line, thus not used for flipping
05468          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
05469          *    pixel by pixel. */
05470         if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
05471                 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
05472         {
05473             TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
05474             fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
05475         }
05476         else
05477         {
05478             TRACE("Using hardware stretching to flip / stretch the texture.\n");
05479             fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
05480         }
05481 
05482         if (!(dst_surface->flags & SFLAG_DONOTFREE))
05483         {
05484             HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
05485             dst_surface->resource.allocatedMemory = NULL;
05486             dst_surface->resource.heapMemory = NULL;
05487         }
05488         else
05489         {
05490             dst_surface->flags &= ~SFLAG_INSYSMEM;
05491         }
05492 
05493         return WINED3D_OK;
05494     }
05495     else if (src_surface)
05496     {
05497         /* Blit from offscreen surface to render target */
05498         struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
05499         DWORD oldCKeyFlags = src_surface->CKeyFlags;
05500 
05501         TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
05502 
05503         if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
05504                 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
05505                 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
05506         {
05507             FIXME("Unsupported blit operation falling back to software\n");
05508             return WINED3DERR_INVALIDCALL;
05509         }
05510 
05511         /* Color keying: Check if we have to do a color keyed blt,
05512          * and if not check if a color key is activated.
05513          *
05514          * Just modify the color keying parameters in the surface and restore them afterwards
05515          * The surface keeps track of the color key last used to load the opengl surface.
05516          * PreLoad will catch the change to the flags and color key and reload if necessary.
05517          */
05518         if (flags & WINEDDBLT_KEYSRC)
05519         {
05520             /* Use color key from surface */
05521         }
05522         else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
05523         {
05524             /* Use color key from DDBltFx */
05525             src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
05526             src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
05527         }
05528         else
05529         {
05530             /* Do not use color key */
05531             src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
05532         }
05533 
05534         surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
05535                 src_surface, src_rect, dst_surface, dst_rect);
05536 
05537         /* Restore the color key parameters */
05538         src_surface->CKeyFlags = oldCKeyFlags;
05539         src_surface->src_blt_color_key = old_blt_key;
05540 
05541         surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
05542 
05543         return WINED3D_OK;
05544     }
05545 
05546     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
05547     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
05548     return WINED3DERR_INVALIDCALL;
05549 }
05550 
05551 /* GL locking is done by the caller */
05552 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
05553         GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
05554 {
05555     struct wined3d_device *device = surface->resource.device;
05556     const struct wined3d_gl_info *gl_info = context->gl_info;
05557     GLint compare_mode = GL_NONE;
05558     struct blt_info info;
05559     GLint old_binding = 0;
05560     RECT rect;
05561 
05562     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
05563 
05564     glDisable(GL_CULL_FACE);
05565     glDisable(GL_BLEND);
05566     glDisable(GL_ALPHA_TEST);
05567     glDisable(GL_SCISSOR_TEST);
05568     glDisable(GL_STENCIL_TEST);
05569     glEnable(GL_DEPTH_TEST);
05570     glDepthFunc(GL_ALWAYS);
05571     glDepthMask(GL_TRUE);
05572     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
05573     glViewport(x, y, w, h);
05574 
05575     SetRect(&rect, 0, h, w, 0);
05576     surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
05577     context_active_texture(context, context->gl_info, 0);
05578     glGetIntegerv(info.binding, &old_binding);
05579     glBindTexture(info.bind_target, texture);
05580     if (gl_info->supported[ARB_SHADOW])
05581     {
05582         glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
05583         if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
05584     }
05585 
05586     device->shader_backend->shader_select_depth_blt(device->shader_priv,
05587             gl_info, info.tex_type, &surface->ds_current_size);
05588 
05589     glBegin(GL_TRIANGLE_STRIP);
05590     glTexCoord3fv(info.coords[0]);
05591     glVertex2f(-1.0f, -1.0f);
05592     glTexCoord3fv(info.coords[1]);
05593     glVertex2f(1.0f, -1.0f);
05594     glTexCoord3fv(info.coords[2]);
05595     glVertex2f(-1.0f, 1.0f);
05596     glTexCoord3fv(info.coords[3]);
05597     glVertex2f(1.0f, 1.0f);
05598     glEnd();
05599 
05600     if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
05601     glBindTexture(info.bind_target, old_binding);
05602 
05603     glPopAttrib();
05604 
05605     device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
05606 }
05607 
05608 void surface_modify_ds_location(struct wined3d_surface *surface,
05609         DWORD location, UINT w, UINT h)
05610 {
05611     TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
05612 
05613     if (location & ~(SFLAG_LOCATIONS | SFLAG_LOST))
05614         FIXME("Invalid location (%#x) specified.\n", location);
05615 
05616     if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
05617             || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
05618     {
05619         if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
05620         {
05621             TRACE("Passing to container.\n");
05622             wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
05623         }
05624     }
05625 
05626     surface->ds_current_size.cx = w;
05627     surface->ds_current_size.cy = h;
05628     surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_LOST);
05629     surface->flags |= location;
05630 }
05631 
05632 /* Context activation is done by the caller. */
05633 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
05634 {
05635     struct wined3d_device *device = surface->resource.device;
05636     GLsizei w, h;
05637 
05638     TRACE("surface %p, new location %#x.\n", surface, location);
05639 
05640     /* TODO: Make this work for modes other than FBO */
05641     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
05642 
05643     if (!(surface->flags & location))
05644     {
05645         w = surface->ds_current_size.cx;
05646         h = surface->ds_current_size.cy;
05647         surface->ds_current_size.cx = 0;
05648         surface->ds_current_size.cy = 0;
05649     }
05650     else
05651     {
05652         w = surface->resource.width;
05653         h = surface->resource.height;
05654     }
05655 
05656     if (surface->ds_current_size.cx == surface->resource.width
05657             && surface->ds_current_size.cy == surface->resource.height)
05658     {
05659         TRACE("Location (%#x) is already up to date.\n", location);
05660         return;
05661     }
05662 
05663     if (surface->current_renderbuffer)
05664     {
05665         FIXME("Not supported with fixed up depth stencil.\n");
05666         return;
05667     }
05668 
05669     if (surface->flags & SFLAG_LOST)
05670     {
05671         TRACE("Surface was discarded, no need copy data.\n");
05672         switch (location)
05673         {
05674             case SFLAG_INTEXTURE:
05675                 surface_prepare_texture(surface, context, FALSE);
05676                 break;
05677             case SFLAG_INRB_MULTISAMPLE:
05678                 surface_prepare_rb(surface, context->gl_info, TRUE);
05679                 break;
05680             case SFLAG_INDRAWABLE:
05681                 /* Nothing to do */
05682                 break;
05683             default:
05684                 FIXME("Unhandled location %#x\n", location);
05685         }
05686         surface->flags &= ~SFLAG_LOST;
05687         surface->flags |= location;
05688         surface->ds_current_size.cx = surface->resource.width;
05689         surface->ds_current_size.cy = surface->resource.height;
05690         return;
05691     }
05692 
05693     if (!(surface->flags & SFLAG_LOCATIONS))
05694     {
05695         FIXME("No up to date depth stencil location.\n");
05696         surface->flags |= location;
05697         surface->ds_current_size.cx = surface->resource.width;
05698         surface->ds_current_size.cy = surface->resource.height;
05699         return;
05700     }
05701 
05702     if (location == SFLAG_INTEXTURE)
05703     {
05704         GLint old_binding = 0;
05705         GLenum bind_target;
05706 
05707         /* The render target is allowed to be smaller than the depth/stencil
05708          * buffer, so the onscreen depth/stencil buffer is potentially smaller
05709          * than the offscreen surface. Don't overwrite the offscreen surface
05710          * with undefined data. */
05711         w = min(w, context->swapchain->desc.backbuffer_width);
05712         h = min(h, context->swapchain->desc.backbuffer_height);
05713 
05714         TRACE("Copying onscreen depth buffer to depth texture.\n");
05715 
05716         ENTER_GL();
05717 
05718         if (!device->depth_blt_texture)
05719         {
05720             glGenTextures(1, &device->depth_blt_texture);
05721         }
05722 
05723         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
05724          * directly on the FBO texture. That's because we need to flip. */
05725         context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
05726                 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
05727         if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
05728         {
05729             glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
05730             bind_target = GL_TEXTURE_RECTANGLE_ARB;
05731         }
05732         else
05733         {
05734             glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
05735             bind_target = GL_TEXTURE_2D;
05736         }
05737         glBindTexture(bind_target, device->depth_blt_texture);
05738         /* We use GL_DEPTH_COMPONENT instead of the surface's specific
05739          * internal format, because the internal format might include stencil
05740          * data. In principle we should copy stencil data as well, but unless
05741          * the driver supports stencil export it's hard to do, and doesn't
05742          * seem to be needed in practice. If the hardware doesn't support
05743          * writing stencil data, the glCopyTexImage2D() call might trigger
05744          * software fallbacks. */
05745         glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
05746         glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
05747         glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
05748         glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
05749         glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
05750         glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
05751         glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
05752         glBindTexture(bind_target, old_binding);
05753 
05754         context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
05755                 NULL, surface, SFLAG_INTEXTURE);
05756         context_set_draw_buffer(context, GL_NONE);
05757         glReadBuffer(GL_NONE);
05758 
05759         /* Do the actual blit */
05760         surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
05761         checkGLcall("depth_blt");
05762 
05763         context_invalidate_state(context, STATE_FRAMEBUFFER);
05764 
05765         LEAVE_GL();
05766 
05767         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
05768     }
05769     else if (location == SFLAG_INDRAWABLE)
05770     {
05771         TRACE("Copying depth texture to onscreen depth buffer.\n");
05772 
05773         ENTER_GL();
05774 
05775         context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
05776                 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
05777         surface_depth_blt(surface, context, surface->texture_name,
05778                 0, surface->pow2Height - h, w, h, surface->texture_target);
05779         checkGLcall("depth_blt");
05780 
05781         context_invalidate_state(context, STATE_FRAMEBUFFER);
05782 
05783         LEAVE_GL();
05784 
05785         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
05786     }
05787     else
05788     {
05789         ERR("Invalid location (%#x) specified.\n", location);
05790     }
05791 
05792     surface->flags |= location;
05793     surface->ds_current_size.cx = surface->resource.width;
05794     surface->ds_current_size.cy = surface->resource.height;
05795 }
05796 
05797 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
05798 {
05799     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
05800     struct wined3d_surface *overlay;
05801 
05802     TRACE("surface %p, location %s, persistent %#x.\n",
05803             surface, debug_surflocation(location), persistent);
05804 
05805     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
05806             && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
05807             && (location & SFLAG_INDRAWABLE))
05808         ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
05809 
05810     if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
05811             && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
05812         location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
05813 
05814     if (persistent)
05815     {
05816         if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
05817                 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
05818         {
05819             if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
05820             {
05821                 TRACE("Passing to container.\n");
05822                 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
05823             }
05824         }
05825         surface->flags &= ~SFLAG_LOCATIONS;
05826         surface->flags |= location;
05827 
05828         /* Redraw emulated overlays, if any */
05829         if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
05830         {
05831             LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
05832             {
05833                 surface_draw_overlay(overlay);
05834             }
05835         }
05836     }
05837     else
05838     {
05839         if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
05840         {
05841             if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
05842             {
05843                 TRACE("Passing to container\n");
05844                 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
05845             }
05846         }
05847         surface->flags &= ~location;
05848     }
05849 
05850     if (!(surface->flags & SFLAG_LOCATIONS))
05851     {
05852         ERR("Surface %p does not have any up to date location.\n", surface);
05853     }
05854 }
05855 
05856 static DWORD resource_access_from_location(DWORD location)
05857 {
05858     switch (location)
05859     {
05860         case SFLAG_INSYSMEM:
05861             return WINED3D_RESOURCE_ACCESS_CPU;
05862 
05863         case SFLAG_INDRAWABLE:
05864         case SFLAG_INSRGBTEX:
05865         case SFLAG_INTEXTURE:
05866         case SFLAG_INRB_MULTISAMPLE:
05867         case SFLAG_INRB_RESOLVED:
05868             return WINED3D_RESOURCE_ACCESS_GPU;
05869 
05870         default:
05871             FIXME("Unhandled location %#x.\n", location);
05872             return 0;
05873     }
05874 }
05875 
05876 static void surface_load_sysmem(struct wined3d_surface *surface,
05877         const struct wined3d_gl_info *gl_info, const RECT *rect)
05878 {
05879     surface_prepare_system_memory(surface);
05880 
05881     if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
05882         surface_load_location(surface, SFLAG_INTEXTURE, NULL);
05883 
05884     /* Download the surface to system memory. */
05885     if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
05886     {
05887         struct wined3d_device *device = surface->resource.device;
05888         struct wined3d_context *context;
05889 
05890         /* TODO: Use already acquired context when possible. */
05891         context = context_acquire(device, NULL);
05892 
05893         surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
05894         surface_download_data(surface, gl_info);
05895 
05896         context_release(context);
05897 
05898         return;
05899     }
05900 
05901     if (surface->flags & SFLAG_INDRAWABLE)
05902     {
05903         read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
05904                 wined3d_surface_get_pitch(surface));
05905         return;
05906     }
05907 
05908     FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
05909             surface, surface->flags & SFLAG_LOCATIONS);
05910 }
05911 
05912 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
05913         const struct wined3d_gl_info *gl_info, const RECT *rect)
05914 {
05915     struct wined3d_device *device = surface->resource.device;
05916     struct wined3d_format format;
05917     CONVERT_TYPES convert;
05918     UINT byte_count;
05919     BYTE *mem;
05920 
05921     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
05922     {
05923         ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
05924         return WINED3DERR_INVALIDCALL;
05925     }
05926 
05927     if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
05928         surface_load_location(surface, SFLAG_INTEXTURE, NULL);
05929 
05930     if (surface->flags & SFLAG_INTEXTURE)
05931     {
05932         RECT r;
05933 
05934         surface_get_rect(surface, rect, &r);
05935         surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
05936 
05937         return WINED3D_OK;
05938     }
05939 
05940     if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
05941     {
05942         /* This needs colorspace conversion from sRGB to RGB. We take the slow
05943          * path through sysmem. */
05944         surface_load_location(surface, SFLAG_INSYSMEM, rect);
05945     }
05946 
05947     d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
05948 
05949     /* Don't use PBOs for converted surfaces. During PBO conversion we look at
05950      * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
05951      * called. */
05952     if ((convert != NO_CONVERSION) && (surface->flags & SFLAG_PBO))
05953     {
05954         struct wined3d_context *context;
05955 
05956         TRACE("Removing the pbo attached to surface %p.\n", surface);
05957 
05958         /* TODO: Use already acquired context when possible. */
05959         context = context_acquire(device, NULL);
05960 
05961         surface_remove_pbo(surface, gl_info);
05962 
05963         context_release(context);
05964     }
05965 
05966     if ((convert != NO_CONVERSION) && surface->resource.allocatedMemory)
05967     {
05968         UINT height = surface->resource.height;
05969         UINT width = surface->resource.width;
05970         UINT src_pitch, dst_pitch;
05971 
05972         byte_count = format.conv_byte_count;
05973         src_pitch = wined3d_surface_get_pitch(surface);
05974 
05975         /* Stick to the alignment for the converted surface too, makes it
05976          * easier to load the surface. */
05977         dst_pitch = width * byte_count;
05978         dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
05979 
05980         if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
05981         {
05982             ERR("Out of memory (%u).\n", dst_pitch * height);
05983             return E_OUTOFMEMORY;
05984         }
05985 
05986         d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
05987                 src_pitch, width, height, dst_pitch, convert, surface);
05988 
05989         surface->flags |= SFLAG_CONVERTED;
05990     }
05991     else
05992     {
05993         surface->flags &= ~SFLAG_CONVERTED;
05994         mem = surface->resource.allocatedMemory;
05995         byte_count = format.byte_count;
05996     }
05997 
05998     flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
05999 
06000     /* Don't delete PBO memory. */
06001     if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
06002         HeapFree(GetProcessHeap(), 0, mem);
06003 
06004     return WINED3D_OK;
06005 }
06006 
06007 static HRESULT surface_load_texture(struct wined3d_surface *surface,
06008         const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
06009 {
06010     RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
06011     struct wined3d_device *device = surface->resource.device;
06012     struct wined3d_context *context;
06013     UINT width, src_pitch, dst_pitch;
06014     struct wined3d_bo_address data;
06015     struct wined3d_format format;
06016     POINT dst_point = {0, 0};
06017     CONVERT_TYPES convert;
06018     BYTE *mem;
06019 
06020     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
06021             && surface_is_offscreen(surface)
06022             && (surface->flags & SFLAG_INDRAWABLE))
06023     {
06024         surface_load_fb_texture(surface, srgb);
06025 
06026         return WINED3D_OK;
06027     }
06028 
06029     if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
06030             && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
06031             && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
06032                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
06033                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
06034     {
06035         if (srgb)
06036             surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
06037                     &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
06038         else
06039             surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
06040                     &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
06041 
06042         return WINED3D_OK;
06043     }
06044 
06045     if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
06046             && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
06047             && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
06048                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
06049                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
06050     {
06051         DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
06052         DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
06053         RECT rect = {0, 0, surface->resource.width, surface->resource.height};
06054 
06055         surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
06056                 &rect, surface, dst_location, &rect);
06057 
06058         return WINED3D_OK;
06059     }
06060 
06061     /* Upload from system memory */
06062 
06063     d3dfmt_get_conv(surface, TRUE /* We need color keying */,
06064             TRUE /* We will use textures */, &format, &convert);
06065 
06066     if (srgb)
06067     {
06068         if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
06069         {
06070             /* Performance warning... */
06071             FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
06072             surface_load_location(surface, SFLAG_INSYSMEM, rect);
06073         }
06074     }
06075     else
06076     {
06077         if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
06078         {
06079             /* Performance warning... */
06080             FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
06081             surface_load_location(surface, SFLAG_INSYSMEM, rect);
06082         }
06083     }
06084 
06085     if (!(surface->flags & SFLAG_INSYSMEM))
06086     {
06087         WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
06088         /* Lets hope we get it from somewhere... */
06089         surface_load_location(surface, SFLAG_INSYSMEM, rect);
06090     }
06091 
06092     /* TODO: Use already acquired context when possible. */
06093     context = context_acquire(device, NULL);
06094 
06095     surface_prepare_texture(surface, context, srgb);
06096     surface_bind_and_dirtify(surface, context, srgb);
06097 
06098     if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
06099     {
06100         surface->flags |= SFLAG_GLCKEY;
06101         surface->gl_color_key = surface->src_blt_color_key;
06102     }
06103     else surface->flags &= ~SFLAG_GLCKEY;
06104 
06105     width = surface->resource.width;
06106     src_pitch = wined3d_surface_get_pitch(surface);
06107 
06108     /* Don't use PBOs for converted surfaces. During PBO conversion we look at
06109      * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
06110      * called. */
06111     if ((convert != NO_CONVERSION || format.convert) && (surface->flags & SFLAG_PBO))
06112     {
06113         TRACE("Removing the pbo attached to surface %p.\n", surface);
06114         surface_remove_pbo(surface, gl_info);
06115     }
06116 
06117     if (format.convert)
06118     {
06119         /* This code is entered for texture formats which need a fixup. */
06120         UINT height = surface->resource.height;
06121 
06122         /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
06123         dst_pitch = width * format.conv_byte_count;
06124         dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
06125 
06126         if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
06127         {
06128             ERR("Out of memory (%u).\n", dst_pitch * height);
06129             context_release(context);
06130             return E_OUTOFMEMORY;
06131         }
06132         format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
06133         format.byte_count = format.conv_byte_count;
06134         src_pitch = dst_pitch;
06135     }
06136     else if (convert != NO_CONVERSION && surface->resource.allocatedMemory)
06137     {
06138         /* This code is only entered for color keying fixups */
06139         UINT height = surface->resource.height;
06140 
06141         /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
06142         dst_pitch = width * format.conv_byte_count;
06143         dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
06144 
06145         if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
06146         {
06147             ERR("Out of memory (%u).\n", dst_pitch * height);
06148             context_release(context);
06149             return E_OUTOFMEMORY;
06150         }
06151         d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
06152                 width, height, dst_pitch, convert, surface);
06153         format.byte_count = format.conv_byte_count;
06154         src_pitch = dst_pitch;
06155     }
06156     else
06157     {
06158         mem = surface->resource.allocatedMemory;
06159     }
06160 
06161     data.buffer_object = surface->flags & SFLAG_PBO ? surface->pbo : 0;
06162     data.addr = mem;
06163     surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
06164 
06165     context_release(context);
06166 
06167     /* Don't delete PBO memory. */
06168     if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
06169         HeapFree(GetProcessHeap(), 0, mem);
06170 
06171     return WINED3D_OK;
06172 }
06173 
06174 static void surface_multisample_resolve(struct wined3d_surface *surface)
06175 {
06176     RECT rect = {0, 0, surface->resource.width, surface->resource.height};
06177 
06178     if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
06179         ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
06180 
06181     surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
06182             surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
06183 }
06184 
06185 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
06186 {
06187     struct wined3d_device *device = surface->resource.device;
06188     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
06189     HRESULT hr;
06190 
06191     TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
06192 
06193     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
06194     {
06195         if (location == SFLAG_INTEXTURE)
06196         {
06197             struct wined3d_context *context = context_acquire(device, NULL);
06198             surface_load_ds_location(surface, context, location);
06199             context_release(context);
06200             return WINED3D_OK;
06201         }
06202         else
06203         {
06204             FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
06205             return WINED3DERR_INVALIDCALL;
06206         }
06207     }
06208 
06209     if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
06210         location = SFLAG_INTEXTURE;
06211 
06212     if (surface->flags & location)
06213     {
06214         TRACE("Location already up to date.\n");
06215 
06216         if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
06217                 && surface_need_pbo(surface, gl_info))
06218             surface_load_pbo(surface, gl_info);
06219 
06220         return WINED3D_OK;
06221     }
06222 
06223     if (WARN_ON(d3d_surface))
06224     {
06225         DWORD required_access = resource_access_from_location(location);
06226         if ((surface->resource.access_flags & required_access) != required_access)
06227             WARN("Operation requires %#x access, but surface only has %#x.\n",
06228                     required_access, surface->resource.access_flags);
06229     }
06230 
06231     if (!(surface->flags & SFLAG_LOCATIONS))
06232     {
06233         ERR("Surface %p does not have any up to date location.\n", surface);
06234         surface->flags |= SFLAG_LOST;
06235         return WINED3DERR_DEVICELOST;
06236     }
06237 
06238     switch (location)
06239     {
06240         case SFLAG_INSYSMEM:
06241             surface_load_sysmem(surface, gl_info, rect);
06242             break;
06243 
06244         case SFLAG_INDRAWABLE:
06245             if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
06246                 return hr;
06247             break;
06248 
06249         case SFLAG_INRB_RESOLVED:
06250             surface_multisample_resolve(surface);
06251             break;
06252 
06253         case SFLAG_INTEXTURE:
06254         case SFLAG_INSRGBTEX:
06255             if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
06256                 return hr;
06257             break;
06258 
06259         default:
06260             ERR("Don't know how to handle location %#x.\n", location);
06261             break;
06262     }
06263 
06264     if (!rect)
06265     {
06266         surface->flags |= location;
06267 
06268         if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
06269             surface_evict_sysmem(surface);
06270     }
06271 
06272     if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
06273             && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
06274     {
06275         surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
06276     }
06277 
06278     return WINED3D_OK;
06279 }
06280 
06281 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
06282 {
06283     struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
06284 
06285     /* Not on a swapchain - must be offscreen */
06286     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
06287 
06288     /* The front buffer is always onscreen */
06289     if (surface == swapchain->front_buffer) return FALSE;
06290 
06291     /* If the swapchain is rendered to an FBO, the backbuffer is
06292      * offscreen, otherwise onscreen */
06293     return swapchain->render_to_fbo;
06294 }
06295 
06296 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
06297 /* Context activation is done by the caller. */
06298 static void ffp_blit_free(struct wined3d_device *device) { }
06299 
06300 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
06301 /* Context activation is done by the caller. */
06302 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
06303 {
06304     BYTE table[256][4];
06305     BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
06306 
06307     d3dfmt_p8_init_palette(surface, table, colorkey_active);
06308 
06309     TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
06310     ENTER_GL();
06311     GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
06312     LEAVE_GL();
06313 }
06314 
06315 /* Context activation is done by the caller. */
06316 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
06317 {
06318     enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
06319 
06320     /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
06321      * else the surface is converted in software at upload time in LoadLocation.
06322      */
06323     if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
06324             && context->gl_info->supported[EXT_PALETTED_TEXTURE])
06325         ffp_blit_p8_upload_palette(surface, context->gl_info);
06326 
06327     ENTER_GL();
06328     glEnable(surface->texture_target);
06329     checkGLcall("glEnable(surface->texture_target)");
06330     LEAVE_GL();
06331     return WINED3D_OK;
06332 }
06333 
06334 /* Context activation is done by the caller. */
06335 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
06336 {
06337     ENTER_GL();
06338     glDisable(GL_TEXTURE_2D);
06339     checkGLcall("glDisable(GL_TEXTURE_2D)");
06340     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
06341     {
06342         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
06343         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
06344     }
06345     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
06346     {
06347         glDisable(GL_TEXTURE_RECTANGLE_ARB);
06348         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
06349     }
06350     LEAVE_GL();
06351 }
06352 
06353 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
06354         const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
06355         const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
06356 {
06357     enum complex_fixup src_fixup;
06358 
06359     switch (blit_op)
06360     {
06361         case WINED3D_BLIT_OP_COLOR_BLIT:
06362             if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
06363                 return FALSE;
06364 
06365             src_fixup = get_complex_fixup(src_format->color_fixup);
06366             if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
06367             {
06368                 TRACE("Checking support for fixup:\n");
06369                 dump_color_fixup_desc(src_format->color_fixup);
06370             }
06371 
06372             if (!is_identity_fixup(dst_format->color_fixup))
06373             {
06374                 TRACE("Destination fixups are not supported\n");
06375                 return FALSE;
06376             }
06377 
06378             if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
06379             {
06380                 TRACE("P8 fixup supported\n");
06381                 return TRUE;
06382             }
06383 
06384             /* We only support identity conversions. */
06385             if (is_identity_fixup(src_format->color_fixup))
06386             {
06387                 TRACE("[OK]\n");
06388                 return TRUE;
06389             }
06390 
06391             TRACE("[FAILED]\n");
06392             return FALSE;
06393 
06394         case WINED3D_BLIT_OP_COLOR_FILL:
06395             if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
06396                 return FALSE;
06397 
06398             if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
06399             {
06400                 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
06401                     return FALSE;
06402             }
06403             else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
06404             {
06405                 TRACE("Color fill not supported\n");
06406                 return FALSE;
06407             }
06408 
06409             /* FIXME: We should reject color fills on formats with fixups,
06410              * but this would break P8 color fills for example. */
06411 
06412             return TRUE;
06413 
06414         case WINED3D_BLIT_OP_DEPTH_FILL:
06415             return TRUE;
06416 
06417         default:
06418             TRACE("Unsupported blit_op=%d\n", blit_op);
06419             return FALSE;
06420     }
06421 }
06422 
06423 /* Do not call while under the GL lock. */
06424 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
06425         const RECT *dst_rect, const struct wined3d_color *color)
06426 {
06427     const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
06428     struct wined3d_fb_state fb = {&dst_surface, NULL};
06429 
06430     return device_clear_render_targets(device, 1, &fb,
06431             1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
06432 }
06433 
06434 /* Do not call while under the GL lock. */
06435 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
06436         struct wined3d_surface *surface, const RECT *rect, float depth)
06437 {
06438     const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
06439     struct wined3d_fb_state fb = {NULL, surface};
06440 
06441     return device_clear_render_targets(device, 0, &fb,
06442             1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
06443 }
06444 
06445 const struct blit_shader ffp_blit =  {
06446     ffp_blit_alloc,
06447     ffp_blit_free,
06448     ffp_blit_set,
06449     ffp_blit_unset,
06450     ffp_blit_supported,
06451     ffp_blit_color_fill,
06452     ffp_blit_depth_fill,
06453 };
06454 
06455 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
06456 {
06457     return WINED3D_OK;
06458 }
06459 
06460 /* Context activation is done by the caller. */
06461 static void cpu_blit_free(struct wined3d_device *device)
06462 {
06463 }
06464 
06465 /* Context activation is done by the caller. */
06466 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
06467 {
06468     return WINED3D_OK;
06469 }
06470 
06471 /* Context activation is done by the caller. */
06472 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
06473 {
06474 }
06475 
06476 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
06477         const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
06478         const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
06479 {
06480     if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
06481     {
06482         return TRUE;
06483     }
06484 
06485     return FALSE;
06486 }
06487 
06488 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
06489         UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
06490         const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
06491 {
06492     UINT row_block_count;
06493     const BYTE *src_row;
06494     BYTE *dst_row;
06495     UINT x, y;
06496 
06497     src_row = src_data;
06498     dst_row = dst_data;
06499 
06500     row_block_count = (update_w + format->block_width - 1) / format->block_width;
06501 
06502     if (!flags)
06503     {
06504         for (y = 0; y < update_h; y += format->block_height)
06505         {
06506             memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
06507             src_row += src_pitch;
06508             dst_row += dst_pitch;
06509         }
06510 
06511         return WINED3D_OK;
06512     }
06513 
06514     if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
06515     {
06516         src_row += (((update_h / format->block_height) - 1) * src_pitch);
06517 
06518         switch (format->id)
06519         {
06520             case WINED3DFMT_DXT1:
06521                 for (y = 0; y < update_h; y += format->block_height)
06522                 {
06523                     struct block
06524                     {
06525                         WORD color[2];
06526                         BYTE control_row[4];
06527                     };
06528 
06529                     const struct block *s = (const struct block *)src_row;
06530                     struct block *d = (struct block *)dst_row;
06531 
06532                     for (x = 0; x < row_block_count; ++x)
06533                     {
06534                         d[x].color[0] = s[x].color[0];
06535                         d[x].color[1] = s[x].color[1];
06536                         d[x].control_row[0] = s[x].control_row[3];
06537                         d[x].control_row[1] = s[x].control_row[2];
06538                         d[x].control_row[2] = s[x].control_row[1];
06539                         d[x].control_row[3] = s[x].control_row[0];
06540                     }
06541                     src_row -= src_pitch;
06542                     dst_row += dst_pitch;
06543                 }
06544                 return WINED3D_OK;
06545 
06546             case WINED3DFMT_DXT3:
06547                 for (y = 0; y < update_h; y += format->block_height)
06548                 {
06549                     struct block
06550                     {
06551                         WORD alpha_row[4];
06552                         WORD color[2];
06553                         BYTE control_row[4];
06554                     };
06555 
06556                     const struct block *s = (const struct block *)src_row;
06557                     struct block *d = (struct block *)dst_row;
06558 
06559                     for (x = 0; x < row_block_count; ++x)
06560                     {
06561                         d[x].alpha_row[0] = s[x].alpha_row[3];
06562                         d[x].alpha_row[1] = s[x].alpha_row[2];
06563                         d[x].alpha_row[2] = s[x].alpha_row[1];
06564                         d[x].alpha_row[3] = s[x].alpha_row[0];
06565                         d[x].color[0] = s[x].color[0];
06566                         d[x].color[1] = s[x].color[1];
06567                         d[x].control_row[0] = s[x].control_row[3];
06568                         d[x].control_row[1] = s[x].control_row[2];
06569                         d[x].control_row[2] = s[x].control_row[1];
06570                         d[x].control_row[3] = s[x].control_row[0];
06571                     }
06572                     src_row -= src_pitch;
06573                     dst_row += dst_pitch;
06574                 }
06575                 return WINED3D_OK;
06576 
06577             default:
06578                 FIXME("Compressed flip not implemented for format %s.\n",
06579                         debug_d3dformat(format->id));
06580                 return E_NOTIMPL;
06581         }
06582     }
06583 
06584     FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
06585             debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
06586 
06587     return E_NOTIMPL;
06588 }
06589 
06590 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
06591         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
06592         const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
06593 {
06594     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
06595     const struct wined3d_format *src_format, *dst_format;
06596     struct wined3d_surface *orig_src = src_surface;
06597     struct wined3d_mapped_rect dst_map, src_map;
06598     HRESULT hr = WINED3D_OK;
06599     const BYTE *sbuf;
06600     RECT xdst,xsrc;
06601     BYTE *dbuf;
06602     int x, y;
06603 
06604     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
06605             dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
06606             flags, fx, debug_d3dtexturefiltertype(filter));
06607 
06608     xsrc = *src_rect;
06609 
06610     if (!src_surface)
06611     {
06612         RECT full_rect;
06613 
06614         full_rect.left = 0;
06615         full_rect.top = 0;
06616         full_rect.right = dst_surface->resource.width;
06617         full_rect.bottom = dst_surface->resource.height;
06618         IntersectRect(&xdst, &full_rect, dst_rect);
06619     }
06620     else
06621     {
06622         BOOL clip_horiz, clip_vert;
06623 
06624         xdst = *dst_rect;
06625         clip_horiz = xdst.left < 0 || xdst.right > (int)dst_surface->resource.width;
06626         clip_vert = xdst.top < 0 || xdst.bottom > (int)dst_surface->resource.height;
06627 
06628         if (clip_vert || clip_horiz)
06629         {
06630             /* Now check if this is a special case or not... */
06631             if ((flags & WINEDDBLT_DDFX)
06632                     || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
06633                     || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
06634             {
06635                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
06636                 return WINED3D_OK;
06637             }
06638 
06639             if (clip_horiz)
06640             {
06641                 if (xdst.left < 0)
06642                 {
06643                     xsrc.left -= xdst.left;
06644                     xdst.left = 0;
06645                 }
06646                 if (xdst.right > dst_surface->resource.width)
06647                 {
06648                     xsrc.right -= (xdst.right - (int)dst_surface->resource.width);
06649                     xdst.right = (int)dst_surface->resource.width;
06650                 }
06651             }
06652 
06653             if (clip_vert)
06654             {
06655                 if (xdst.top < 0)
06656                 {
06657                     xsrc.top -= xdst.top;
06658                     xdst.top = 0;
06659                 }
06660                 if (xdst.bottom > dst_surface->resource.height)
06661                 {
06662                     xsrc.bottom -= (xdst.bottom - (int)dst_surface->resource.height);
06663                     xdst.bottom = (int)dst_surface->resource.height;
06664                 }
06665             }
06666 
06667             /* And check if after clipping something is still to be done... */
06668             if ((xdst.right <= 0) || (xdst.bottom <= 0)
06669                     || (xdst.left >= (int)dst_surface->resource.width)
06670                     || (xdst.top >= (int)dst_surface->resource.height)
06671                     || (xsrc.right <= 0) || (xsrc.bottom <= 0)
06672                     || (xsrc.left >= (int)src_surface->resource.width)
06673                     || (xsrc.top >= (int)src_surface->resource.height))
06674             {
06675                 TRACE("Nothing to be done after clipping.\n");
06676                 return WINED3D_OK;
06677             }
06678         }
06679     }
06680 
06681     if (src_surface == dst_surface)
06682     {
06683         wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
06684         src_map = dst_map;
06685         src_format = dst_surface->resource.format;
06686         dst_format = src_format;
06687     }
06688     else
06689     {
06690         dst_format = dst_surface->resource.format;
06691         if (src_surface)
06692         {
06693             if (dst_surface->resource.format->id != src_surface->resource.format->id)
06694             {
06695                 src_surface = surface_convert_format(src_surface, dst_format->id);
06696                 if (!src_surface)
06697                 {
06698                     /* The conv function writes a FIXME */
06699                     WARN("Cannot convert source surface format to dest format.\n");
06700                     goto release;
06701                 }
06702             }
06703             wined3d_surface_map(src_surface, &src_map, NULL, WINED3DLOCK_READONLY);
06704             src_format = src_surface->resource.format;
06705         }
06706         else
06707         {
06708             src_format = dst_format;
06709         }
06710         if (dst_rect)
06711             wined3d_surface_map(dst_surface, &dst_map, &xdst, 0);
06712         else
06713             wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
06714     }
06715 
06716     bpp = dst_surface->resource.format->byte_count;
06717     srcheight = xsrc.bottom - xsrc.top;
06718     srcwidth = xsrc.right - xsrc.left;
06719     dstheight = xdst.bottom - xdst.top;
06720     dstwidth = xdst.right - xdst.left;
06721     width = (xdst.right - xdst.left) * bpp;
06722 
06723     if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
06724     {
06725         TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
06726 
06727         if (src_surface == dst_surface)
06728         {
06729             FIXME("Only plain blits supported on compressed surfaces.\n");
06730             hr = E_NOTIMPL;
06731             goto release;
06732         }
06733 
06734         if (srcheight != dstheight || srcwidth != dstwidth)
06735         {
06736             WARN("Stretching not supported on compressed surfaces.\n");
06737             hr = WINED3DERR_INVALIDCALL;
06738             goto release;
06739         }
06740 
06741         if (srcwidth & (src_format->block_width - 1) || srcheight & (src_format->block_height - 1))
06742         {
06743             WARN("Rectangle not block-aligned.\n");
06744             hr = WINED3DERR_INVALIDCALL;
06745             goto release;
06746         }
06747 
06748         hr = surface_cpu_blt_compressed(src_map.data, dst_map.data,
06749                 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
06750                 src_format, flags, fx);
06751         goto release;
06752     }
06753 
06754     if (dst_rect && src_surface != dst_surface)
06755         dbuf = dst_map.data;
06756     else
06757         dbuf = (BYTE *)dst_map.data + (xdst.top * dst_map.row_pitch) + (xdst.left * bpp);
06758 
06759     /* First, all the 'source-less' blits */
06760     if (flags & WINEDDBLT_COLORFILL)
06761     {
06762         hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
06763         flags &= ~WINEDDBLT_COLORFILL;
06764     }
06765 
06766     if (flags & WINEDDBLT_DEPTHFILL)
06767     {
06768         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
06769     }
06770     if (flags & WINEDDBLT_ROP)
06771     {
06772         /* Catch some degenerate cases here. */
06773         switch (fx->dwROP)
06774         {
06775             case BLACKNESS:
06776                 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
06777                 break;
06778             case 0xAA0029: /* No-op */
06779                 break;
06780             case WHITENESS:
06781                 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
06782                 break;
06783             case SRCCOPY: /* Well, we do that below? */
06784                 break;
06785             default:
06786                 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
06787                 goto error;
06788         }
06789         flags &= ~WINEDDBLT_ROP;
06790     }
06791     if (flags & WINEDDBLT_DDROPS)
06792     {
06793         FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
06794     }
06795     /* Now the 'with source' blits. */
06796     if (src_surface)
06797     {
06798         const BYTE *sbase;
06799         int sx, xinc, sy, yinc;
06800 
06801         if (!dstwidth || !dstheight) /* Hmm... stupid program? */
06802             goto release;
06803 
06804         if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
06805                 && (srcwidth != dstwidth || srcheight != dstheight))
06806         {
06807             /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
06808             FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
06809         }
06810 
06811         sbase = (BYTE *)src_map.data + (xsrc.top * src_map.row_pitch) + xsrc.left * bpp;
06812         xinc = (srcwidth << 16) / dstwidth;
06813         yinc = (srcheight << 16) / dstheight;
06814 
06815         if (!flags)
06816         {
06817             /* No effects, we can cheat here. */
06818             if (dstwidth == srcwidth)
06819             {
06820                 if (dstheight == srcheight)
06821                 {
06822                     /* No stretching in either direction. This needs to be as
06823                      * fast as possible. */
06824                     sbuf = sbase;
06825 
06826                     /* Check for overlapping surfaces. */
06827                     if (src_surface != dst_surface || xdst.top < xsrc.top
06828                             || xdst.right <= xsrc.left || xsrc.right <= xdst.left)
06829                     {
06830                         /* No overlap, or dst above src, so copy from top downwards. */
06831                         for (y = 0; y < dstheight; ++y)
06832                         {
06833                             memcpy(dbuf, sbuf, width);
06834                             sbuf += src_map.row_pitch;
06835                             dbuf += dst_map.row_pitch;
06836                         }
06837                     }
06838                     else if (xdst.top > xsrc.top)
06839                     {
06840                         /* Copy from bottom upwards. */
06841                         sbuf += src_map.row_pitch * dstheight;
06842                         dbuf += dst_map.row_pitch * dstheight;
06843                         for (y = 0; y < dstheight; ++y)
06844                         {
06845                             sbuf -= src_map.row_pitch;
06846                             dbuf -= dst_map.row_pitch;
06847                             memcpy(dbuf, sbuf, width);
06848                         }
06849                     }
06850                     else
06851                     {
06852                         /* Src and dst overlapping on the same line, use memmove. */
06853                         for (y = 0; y < dstheight; ++y)
06854                         {
06855                             memmove(dbuf, sbuf, width);
06856                             sbuf += src_map.row_pitch;
06857                             dbuf += dst_map.row_pitch;
06858                         }
06859                     }
06860                 }
06861                 else
06862                 {
06863                     /* Stretching in y direction only. */
06864                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
06865                     {
06866                         sbuf = sbase + (sy >> 16) * src_map.row_pitch;
06867                         memcpy(dbuf, sbuf, width);
06868                         dbuf += dst_map.row_pitch;
06869                     }
06870                 }
06871             }
06872             else
06873             {
06874                 /* Stretching in X direction. */
06875                 int last_sy = -1;
06876                 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
06877                 {
06878                     sbuf = sbase + (sy >> 16) * src_map.row_pitch;
06879 
06880                     if ((sy >> 16) == (last_sy >> 16))
06881                     {
06882                         /* This source row is the same as last source row -
06883                          * Copy the already stretched row. */
06884                         memcpy(dbuf, dbuf - dst_map.row_pitch, width);
06885                     }
06886                     else
06887                     {
06888 #define STRETCH_ROW(type) \
06889 do { \
06890     const type *s = (const type *)sbuf; \
06891     type *d = (type *)dbuf; \
06892     for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
06893         d[x] = s[sx >> 16]; \
06894 } while(0)
06895 
06896                         switch(bpp)
06897                         {
06898                             case 1:
06899                                 STRETCH_ROW(BYTE);
06900                                 break;
06901                             case 2:
06902                                 STRETCH_ROW(WORD);
06903                                 break;
06904                             case 4:
06905                                 STRETCH_ROW(DWORD);
06906                                 break;
06907                             case 3:
06908                             {
06909                                 const BYTE *s;
06910                                 BYTE *d = dbuf;
06911                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
06912                                 {
06913                                     DWORD pixel;
06914 
06915                                     s = sbuf + 3 * (sx >> 16);
06916                                     pixel = s[0] | (s[1] << 8) | (s[2] << 16);
06917                                     d[0] = (pixel      ) & 0xff;
06918                                     d[1] = (pixel >>  8) & 0xff;
06919                                     d[2] = (pixel >> 16) & 0xff;
06920                                     d += 3;
06921                                 }
06922                                 break;
06923                             }
06924                             default:
06925                                 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
06926                                 hr = WINED3DERR_NOTAVAILABLE;
06927                                 goto error;
06928                         }
06929 #undef STRETCH_ROW
06930                     }
06931                     dbuf += dst_map.row_pitch;
06932                     last_sy = sy;
06933                 }
06934             }
06935         }
06936         else
06937         {
06938             LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
06939             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
06940             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
06941             if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
06942             {
06943                 /* The color keying flags are checked for correctness in ddraw */
06944                 if (flags & WINEDDBLT_KEYSRC)
06945                 {
06946                     keylow  = src_surface->src_blt_color_key.color_space_low_value;
06947                     keyhigh = src_surface->src_blt_color_key.color_space_high_value;
06948                 }
06949                 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
06950                 {
06951                     keylow = fx->ddckSrcColorkey.color_space_low_value;
06952                     keyhigh = fx->ddckSrcColorkey.color_space_high_value;
06953                 }
06954 
06955                 if (flags & WINEDDBLT_KEYDEST)
06956                 {
06957                     /* Destination color keys are taken from the source surface! */
06958                     destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
06959                     destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
06960                 }
06961                 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
06962                 {
06963                     destkeylow = fx->ddckDestColorkey.color_space_low_value;
06964                     destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
06965                 }
06966 
06967                 if (bpp == 1)
06968                 {
06969                     keymask = 0xff;
06970                 }
06971                 else
06972                 {
06973                     keymask = src_format->red_mask
06974                             | src_format->green_mask
06975                             | src_format->blue_mask;
06976                 }
06977                 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
06978             }
06979 
06980             if (flags & WINEDDBLT_DDFX)
06981             {
06982                 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
06983                 LONG tmpxy;
06984                 dTopLeft     = dbuf;
06985                 dTopRight    = dbuf + ((dstwidth - 1) * bpp);
06986                 dBottomLeft  = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
06987                 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
06988 
06989                 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
06990                 {
06991                     /* I don't think we need to do anything about this flag */
06992                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
06993                 }
06994                 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
06995                 {
06996                     tmp          = dTopRight;
06997                     dTopRight    = dTopLeft;
06998                     dTopLeft     = tmp;
06999                     tmp          = dBottomRight;
07000                     dBottomRight = dBottomLeft;
07001                     dBottomLeft  = tmp;
07002                     dstxinc = dstxinc * -1;
07003                 }
07004                 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
07005                 {
07006                     tmp          = dTopLeft;
07007                     dTopLeft     = dBottomLeft;
07008                     dBottomLeft  = tmp;
07009                     tmp          = dTopRight;
07010                     dTopRight    = dBottomRight;
07011                     dBottomRight = tmp;
07012                     dstyinc = dstyinc * -1;
07013                 }
07014                 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
07015                 {
07016                     /* I don't think we need to do anything about this flag */
07017                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
07018                 }
07019                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
07020                 {
07021                     tmp          = dBottomRight;
07022                     dBottomRight = dTopLeft;
07023                     dTopLeft     = tmp;
07024                     tmp          = dBottomLeft;
07025                     dBottomLeft  = dTopRight;
07026                     dTopRight    = tmp;
07027                     dstxinc = dstxinc * -1;
07028                     dstyinc = dstyinc * -1;
07029                 }
07030                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
07031                 {
07032                     tmp          = dTopLeft;
07033                     dTopLeft     = dBottomLeft;
07034                     dBottomLeft  = dBottomRight;
07035                     dBottomRight = dTopRight;
07036                     dTopRight    = tmp;
07037                     tmpxy   = dstxinc;
07038                     dstxinc = dstyinc;
07039                     dstyinc = tmpxy;
07040                     dstxinc = dstxinc * -1;
07041                 }
07042                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
07043                 {
07044                     tmp          = dTopLeft;
07045                     dTopLeft     = dTopRight;
07046                     dTopRight    = dBottomRight;
07047                     dBottomRight = dBottomLeft;
07048                     dBottomLeft  = tmp;
07049                     tmpxy   = dstxinc;
07050                     dstxinc = dstyinc;
07051                     dstyinc = tmpxy;
07052                     dstyinc = dstyinc * -1;
07053                 }
07054                 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
07055                 {
07056                     /* I don't think we need to do anything about this flag */
07057                     WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
07058                 }
07059                 dbuf = dTopLeft;
07060                 flags &= ~(WINEDDBLT_DDFX);
07061             }
07062 
07063 #define COPY_COLORKEY_FX(type) \
07064 do { \
07065     const type *s; \
07066     type *d = (type *)dbuf, *dx, tmp; \
07067     for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
07068     { \
07069         s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
07070         dx = d; \
07071         for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
07072         { \
07073             tmp = s[sx >> 16]; \
07074             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
07075                     && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
07076             { \
07077                 dx[0] = tmp; \
07078             } \
07079             dx = (type *)(((BYTE *)dx) + dstxinc); \
07080         } \
07081         d = (type *)(((BYTE *)d) + dstyinc); \
07082     } \
07083 } while(0)
07084 
07085             switch (bpp)
07086             {
07087                 case 1:
07088                     COPY_COLORKEY_FX(BYTE);
07089                     break;
07090                 case 2:
07091                     COPY_COLORKEY_FX(WORD);
07092                     break;
07093                 case 4:
07094                     COPY_COLORKEY_FX(DWORD);
07095                     break;
07096                 case 3:
07097                 {
07098                     const BYTE *s;
07099                     BYTE *d = dbuf, *dx;
07100                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
07101                     {
07102                         sbuf = sbase + (sy >> 16) * src_map.row_pitch;
07103                         dx = d;
07104                         for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
07105                         {
07106                             DWORD pixel, dpixel = 0;
07107                             s = sbuf + 3 * (sx>>16);
07108                             pixel = s[0] | (s[1] << 8) | (s[2] << 16);
07109                             dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
07110                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
07111                                     && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
07112                             {
07113                                 dx[0] = (pixel      ) & 0xff;
07114                                 dx[1] = (pixel >>  8) & 0xff;
07115                                 dx[2] = (pixel >> 16) & 0xff;
07116                             }
07117                             dx += dstxinc;
07118                         }
07119                         d += dstyinc;
07120                     }
07121                     break;
07122                 }
07123                 default:
07124                     FIXME("%s color-keyed blit not implemented for bpp %u!\n",
07125                           (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
07126                     hr = WINED3DERR_NOTAVAILABLE;
07127                     goto error;
07128 #undef COPY_COLORKEY_FX
07129             }
07130         }
07131     }
07132 
07133 error:
07134     if (flags && FIXME_ON(d3d_surface))
07135     {
07136         FIXME("\tUnsupported flags: %#x.\n", flags);
07137     }
07138 
07139 release:
07140     wined3d_surface_unmap(dst_surface);
07141     if (src_surface && src_surface != dst_surface)
07142         wined3d_surface_unmap(src_surface);
07143     /* Release the converted surface, if any. */
07144     if (src_surface && src_surface != orig_src)
07145         wined3d_surface_decref(src_surface);
07146 
07147     return hr;
07148 }
07149 
07150 /* Do not call while under the GL lock. */
07151 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
07152         const RECT *dst_rect, const struct wined3d_color *color)
07153 {
07154     static const RECT src_rect;
07155     WINEDDBLTFX BltFx;
07156 
07157     memset(&BltFx, 0, sizeof(BltFx));
07158     BltFx.dwSize = sizeof(BltFx);
07159     BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
07160     return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
07161             WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
07162 }
07163 
07164 /* Do not call while under the GL lock. */
07165 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
07166         struct wined3d_surface *surface, const RECT *rect, float depth)
07167 {
07168     FIXME("Depth filling not implemented by cpu_blit.\n");
07169     return WINED3DERR_INVALIDCALL;
07170 }
07171 
07172 const struct blit_shader cpu_blit =  {
07173     cpu_blit_alloc,
07174     cpu_blit_free,
07175     cpu_blit_set,
07176     cpu_blit_unset,
07177     cpu_blit_supported,
07178     cpu_blit_color_fill,
07179     cpu_blit_depth_fill,
07180 };
07181 
07182 static HRESULT surface_init(struct wined3d_surface *surface, WINED3DSURFTYPE surface_type, UINT alignment,
07183         UINT width, UINT height, UINT level, enum wined3d_multisample_type multisample_type,
07184         UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
07185         enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
07186 {
07187     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
07188     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
07189     BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
07190     unsigned int resource_size;
07191     HRESULT hr;
07192 
07193     if (multisample_quality > 0)
07194     {
07195         FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
07196         multisample_quality = 0;
07197     }
07198 
07199     /* Quick lockable sanity check.
07200      * TODO: remove this after surfaces, usage and lockability have been debugged properly
07201      * this function is too deep to need to care about things like this.
07202      * Levels need to be checked too, since they all affect what can be done. */
07203     switch (pool)
07204     {
07205         case WINED3D_POOL_SCRATCH:
07206             if (!lockable)
07207             {
07208                 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
07209                         "which are mutually exclusive, setting lockable to TRUE.\n");
07210                 lockable = TRUE;
07211             }
07212             break;
07213 
07214         case WINED3D_POOL_SYSTEM_MEM:
07215             if (!lockable)
07216                 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
07217             break;
07218 
07219         case WINED3D_POOL_MANAGED:
07220             if (usage & WINED3DUSAGE_DYNAMIC)
07221                 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
07222             break;
07223 
07224         case WINED3D_POOL_DEFAULT:
07225             if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
07226                 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
07227             break;
07228 
07229         default:
07230             FIXME("Unknown pool %#x.\n", pool);
07231             break;
07232     };
07233 
07234     if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
07235         FIXME("Trying to create a render target that isn't in the default pool.\n");
07236 
07237     /* FIXME: Check that the format is supported by the device. */
07238 
07239     resource_size = wined3d_format_calculate_size(format, alignment, width, height);
07240     if (!resource_size)
07241         return WINED3DERR_INVALIDCALL;
07242 
07243     surface->surface_type = surface_type;
07244 
07245     switch (surface_type)
07246     {
07247         case SURFACE_OPENGL:
07248             surface->surface_ops = &surface_ops;
07249             break;
07250 
07251         case SURFACE_GDI:
07252             surface->surface_ops = &gdi_surface_ops;
07253             break;
07254 
07255         default:
07256             ERR("Requested unknown surface implementation %#x.\n", surface_type);
07257             return WINED3DERR_INVALIDCALL;
07258     }
07259 
07260     hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
07261             multisample_type, multisample_quality, usage, pool, width, height, 1,
07262             resource_size, parent, parent_ops, &surface_resource_ops);
07263     if (FAILED(hr))
07264     {
07265         WARN("Failed to initialize resource, returning %#x.\n", hr);
07266         return hr;
07267     }
07268 
07269     /* "Standalone" surface. */
07270     surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
07271 
07272     surface->texture_level = level;
07273     list_init(&surface->overlays);
07274 
07275     /* Flags */
07276     surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
07277     if (flags & WINED3D_SURFACE_DISCARD)
07278         surface->flags |= SFLAG_DISCARD;
07279     if (flags & WINED3D_SURFACE_PIN_SYSMEM)
07280         surface->flags |= SFLAG_PIN_SYSMEM;
07281     if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
07282         surface->flags |= SFLAG_LOCKABLE;
07283     /* I'm not sure if this qualifies as a hack or as an optimization. It
07284      * seems reasonable to assume that lockable render targets will get
07285      * locked, so we might as well set SFLAG_DYNLOCK right at surface
07286      * creation. However, the other reason we want to do this is that several
07287      * ddraw applications access surface memory while the surface isn't
07288      * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
07289      * future locks prevents these from crashing. */
07290     if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
07291         surface->flags |= SFLAG_DYNLOCK;
07292 
07293     /* Mark the texture as dirty so that it gets loaded first time around. */
07294     surface_add_dirty_rect(surface, NULL);
07295     list_init(&surface->renderbuffers);
07296 
07297     TRACE("surface %p, memory %p, size %u\n",
07298             surface, surface->resource.allocatedMemory, surface->resource.size);
07299 
07300     /* Call the private setup routine */
07301     hr = surface->surface_ops->surface_private_setup(surface);
07302     if (FAILED(hr))
07303     {
07304         ERR("Private setup failed, returning %#x\n", hr);
07305         surface_cleanup(surface);
07306         return hr;
07307     }
07308 
07309     /* Similar to lockable rendertargets above, creating the DIB section
07310      * during surface initialization prevents the sysmem pointer from changing
07311      * after a wined3d_surface_getdc() call. */
07312     if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
07313             && SUCCEEDED(surface_create_dib_section(surface)))
07314     {
07315         HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
07316         surface->resource.heapMemory = NULL;
07317         surface->resource.allocatedMemory = surface->dib.bitmap_data;
07318     }
07319 
07320     return hr;
07321 }
07322 
07323 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
07324         enum wined3d_format_id format_id, UINT level, DWORD usage, enum wined3d_pool pool,
07325         enum wined3d_multisample_type multisample_type, DWORD multisample_quality, WINED3DSURFTYPE surface_type,
07326         DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
07327 {
07328     struct wined3d_surface *object;
07329     HRESULT hr;
07330 
07331     TRACE("device %p, width %u, height %u, format %s, level %u\n",
07332             device, width, height, debug_d3dformat(format_id), level);
07333     TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
07334             surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
07335     TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
07336 
07337     if (surface_type == SURFACE_OPENGL && !device->adapter)
07338     {
07339         ERR("OpenGL surfaces are not available without OpenGL.\n");
07340         return WINED3DERR_NOTAVAILABLE;
07341     }
07342 
07343     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
07344     if (!object)
07345     {
07346         ERR("Failed to allocate surface memory.\n");
07347         return WINED3DERR_OUTOFVIDEOMEMORY;
07348     }
07349 
07350     hr = surface_init(object, surface_type, device->surface_alignment, width, height, level,
07351             multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops);
07352     if (FAILED(hr))
07353     {
07354         WARN("Failed to initialize surface, returning %#x.\n", hr);
07355         HeapFree(GetProcessHeap(), 0, object);
07356         return hr;
07357     }
07358 
07359     TRACE("Created surface %p.\n", object);
07360     *surface = object;
07361 
07362     return hr;
07363 }

Generated on Sat May 26 2012 04:20:39 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.