I tried this patch, everything works like before, can't find any regression in apps like ET: QW, Oblivion, all nvidia D3D SDK tests, 3DMarks and others. Titan Quest looks beter, but there are still some issues in menu, game is not working because of gdi32.dll functionality. I create patch for actual git.

Mirek

Mitchell Wheeler napsal(a):
Hi all,

A week or so ago I tried to get a game working in WINE (Titan Quest), however it seems it really needs a proper DIB engine before it'll be playable.

Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :\) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).

You'll probably have to clean up the code to meet your coding standards / etc, maybe remove the custom byte size calculation of compressed images, and some other things - but the functionality is there... i also fixed the existing code that didn't actually do what it was supposed to, heh.

Regards,
Mitchell Wheeler

static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
    IWineD3DDeviceImpl  *This         = (IWineD3DDeviceImpl *) iface;
    /** TODO: remove casts to IWineD3DSurfaceImpl
     *       NOTE: move code to surface to accomplish this
      ****************************************/
IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface; IWineD3DSurfaceImpl *pDestSurface = (IWineD3DSurfaceImpl*)pDestinationSurface;
    int srcWidth, srcHeight;
unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
    WINED3DFORMAT destFormat, srcFormat;
    int srcLeft, srcTop, destLeft, destTop;
    WINED3DPOOL       srcPool, destPool;
    int offset    = 0;
int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
    glDescriptor *glDescription = NULL, *glSrcDescription = NULL;
    GLenum dummy;
    int bpp;
    UINT destByteSize = 0, srcByteSize = 0;
    int destPixelByteSize = 0, srcPixelByteSize = 0;
    CONVERT_TYPES convert = NO_CONVERSION;

    WINED3DSURFACE_DESC  winedesc;

TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
    memset(&winedesc, 0, sizeof(winedesc));
    winedesc.Width  = &srcSurfaceWidth;
    winedesc.Height = &srcSurfaceHeight;
    winedesc.Pool   = &srcPool;
    winedesc.Format = &srcFormat;
    winedesc.Size   = &srcByteSize;

    IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);

    winedesc.Width  = &destSurfaceWidth;
    winedesc.Height = &destSurfaceHeight;
    winedesc.Pool   = &destPool;
    winedesc.Format = &destFormat;
    winedesc.Size   = &destByteSize;

    IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);

if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){ WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
        return WINED3DERR_INVALIDCALL;
    }

/* This call loads the opengl surface directly, instead of copying the surface to the * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
     * copy in sysmem and use regular surface loading.
     */
d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
                    &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
    if(convert != NO_CONVERSION) {
        return IWineD3DSurface_BltFast(pDestinationSurface,
                                        pDestPoint  ? pDestPoint->x : 0,
                                        pDestPoint  ? pDestPoint->y : 0,
pSourceSurface, (RECT *) pSourceRect, 0);
    }

    if (destFormat == WINED3DFMT_UNKNOWN) {
TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
        IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);

        /* Get the update surface description */
        IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
    }

ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);

    ENTER_GL();

    if (GL_SUPPORT(ARB_MULTITEXTURE)) {
        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
        checkGLcall("glActiveTextureARB");
    }

    /* Make sure the surface is loaded and up to date */
    IWineD3DSurface_PreLoad(pDestinationSurface);
    IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
    IWineD3DSurface_GetGlDesc(pDestinationSurface, &glSrcDescription);

/* this needs to be done in lines if the sourceRect != the sourceWidth */ srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth; srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight; srcLeft = pSourceRect ? pSourceRect->left : 0; srcTop = pSourceRect ? pSourceRect->top : 0; destLeft = pDestPoint ? pDestPoint->x : 0; destTop = pDestPoint ? pDestPoint->y : 0;

    // Calculate the rowOffset / offset values, for copying
    #define ISDXTFORMAT(format) \
(format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)

// Calculating this for our selves because I don't have faith in how surface->bytesPerPixel is calculated... destPixelByteSize = destByteSize / (int)(destSurfaceWidth * destSurfaceHeight); srcPixelByteSize = srcByteSize / (int)(srcSurfaceWidth * srcSurfaceHeight);

    if(pSourceRect != NULL)
    {
        // Irregular surface formats
        if (destFormat != srcFormat) {
            FIXME("Can not convert between surface pixel formats...");

// Would require some relatively big code restructuring for rare occurances (that shouldn't even be supported?)

            return WINED3DERR_INVALIDCALL;
        }
        // Uniform surface formats
        else
        {
            if(srcWidth != srcSurfaceWidth || srcLeft > 0)
            {
                rowoffset = srcSurfaceWidth * srcPixelByteSize;
                offset += (srcLeft * srcPixelByteSize);
            }

            if(srcTop > 0)
               offset += srcTop * srcSurfaceWidth * srcPixelByteSize;
        }

    }

    /* Sanity check */
    if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {

        /* need to lock the surface to get the data */
FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
    }

    /* TODO: Cube and volume support */
    if(rowoffset != 0) {
        // Compressed texture
        if (ISDXTFORMAT(destFormat))
        {
            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC))
            {
#if 0
                RECT rect;
                rect.left = destLeft;
                rect.top = destTop;
                rect.right = destLeft + srcWidth;
                rect.bottom = destTop + srcHeight;

                // Lock source/destination regions
                WINED3DLOCKED_RECT destRect, srcRect;

                printf("Locking surfaces...\n");
if( FAILED(IWineD3DSurface_LockRect(pDestinationSurface, &destRect, &rect, 0)) || FAILED(IWineD3DSurface_LockRect(pSourceSurface, &srcRect, pSourceRect, WINED3DLOCK_READONLY)))
                {
// How should we handle this case? Just returning an invalid call for now...
                    return WINED3DERR_INVALIDCALL;
                }

                printf("Surfaces locked, copying contents now... ");
                if(destFormat == WINED3DFMT_DXT1) {
                    printf("DXT1\n");
//memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2)); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 8);
                } else {
                    printf("DXT2-5\n");
//memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 4)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 16);
                }

                // Unlock source/destination regions
                IWineD3DSurface_UnlockRect(pSourceSurface);
                IWineD3DSurface_UnlockRect(pDestinationSurface);
                printf("Unlocking surfaces...\n");
#elif 0
                // Get pointers to the source/destination buffers
unsigned char *dest_data = (unsigned char*)IWineD3DSurface_GetData(pDestinationSurface); const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);

// Copy subsection of source buffer, in to destination buffer.
                unsigned char *dest_ptr = dest_data + offset;
                const unsigned char *src_ptr = src_data + offset;

                size_t i;
                for(i = 0; i < srcHeight; ++i) {
                    memcpy(dest_ptr, src_ptr, srcWidth * srcPixelByteSize);

                    dest_ptr += rowoffset;
                    src_ptr += rowoffset;
                }


                // Upload destination buffer to server
                GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target,
                                                    glDescription->level,
glDescription->glFormatInternal,
                                                    srcWidth,
                                                    srcHeight,
                                                    0,
                                                    destByteSize,
                                                    dest_data));

                checkGLcall("glCompressedTexImage2DARB");
#elif 1
                int blocksize = 16;
                if(destFormat == WINED3DFMT_DXT1)
                    blocksize = 8;

                #define max(a, b) (a > b? a : b)
                srcHeight = max(srcHeight, 4);
                srcWidth = max(srcWidth, 4);
                #undef max

int data_size = (srcWidth / 4) * (srcHeight / 4) * blocksize;
                int row_size = data_size / srcHeight;
                int pixel_size = row_size / srcWidth;
                int stride = srcSurfaceWidth * pixel_size;

unsigned char *temp_buffer = HeapAlloc(GetProcessHeap(), 0, data_size);
                unsigned char *temp_ptr = temp_buffer;

                // Debug info
//printf(" > BytesTotal: %i | BytesPerPixel: %i | RowSize: %i\n", data_size, pixel_size, row_size); //printf(" > Source: %i -> %i, %i -> %i | Dest: %i, %i\n", srcLeft, srcWidth, srcTop, srcHeight, destLeft, destTop); //printf(" > Offset: %i\n", (int)((row_size * srcTop) + srcLeft * pixel_size));

                // Get pointers to the source buffer
const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);
                src_data += (stride * srcTop) + srcLeft * pixel_size;

                size_t i;
                for(i = 0; i < srcHeight; ++i) {
                    memcpy(temp_ptr, src_data, row_size);
                    temp_ptr += row_size;
                    src_data += stride;
                }

                GL_EXTCALL(glCompressedTexSubImage2DARB(
                    glDescription->target,
                    glDescription->level,
                    destLeft,
                    destTop,
                    srcWidth,
                    srcHeight,
                    glDescription->glFormatInternal,
                    data_size,
                    temp_buffer
                ));
                //checkGLcall("glCompressedTexSubImage2DARB");

                HeapFree(GetProcessHeap(), 0, temp_buffer);
#endif
            }
            else
            {
FIXME("TODO: Need to update a DXT compressed texture without hardware support\n");
            }
        }
        // Uncompressed texture
        else
        {
            /* not a whole row so we have to do it a line at a time */
            int j;

/* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */ const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;

            for(j = destTop; j < (srcHeight + destTop); ++j)
            {
                    glTexSubImage2D(glDescription->target
                        ,glDescription->level
                        ,destLeft
                        ,j
                        ,srcWidth
                        ,1
                        ,glDescription->glFormat
                        ,glDescription->glType
                        ,data /* could be quicker using */
                    );
                data += rowoffset;
            }
        }
    } else {
        // Compressed texture
        if (ISDXTFORMAT(destFormat))
        {
            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC))
            {
                int blocksize = 16;
                if(destFormat == WINED3DFMT_DXT1)
                    blocksize = 8;

                #define max(a, b) (a > b? a : b)
int data_size = (max(srcWidth, 4) / 4) * (max(srcHeight, 4) / 4) * blocksize;
                #undef max

//printf(" -> S = %i | CompressedTexImage2D(?, %i, %i, %i, %i, 0, %i, ?)\n", destByteSize, glDescription->level, glDescription->glFormatInternal, srcWidth, srcHeight, data_size); GL_EXTCALL(glCompressedTexSubImage2DARB(glDescription->target,
                                                    glDescription->level,
                                                    destLeft,
                                                    destTop,
                                                    srcWidth,
                                                    srcHeight,
glDescription->glFormatInternal,
                                                    data_size,
IWineD3DSurface_GetData(pSourceSurface)));

                checkGLcall("glCompressedTexImage2DARB");
            }
            else
            {
FIXME("TODO: Need to update a DXT compressed texture without hardware support\n");
            }
        }
        // Uncompressed Texture
        else
        {
            glTexSubImage2D(
                glDescription->target,
                glDescription->level,
                destLeft,
                destTop,
                srcWidth,
                srcHeight,
                glDescription->glFormat,
                glDescription->glType,
                IWineD3DSurface_GetData(pSourceSurface)
            );

            checkGLcall("glTexSubImage2D");
        }
     }

    LEAVE_GL();

    ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
    ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));

    return WINED3D_OK;
}



diff -Naur wine.old/dlls/wined3d/device.c wine/dlls/wined3d/device.c
--- wine.old/dlls/wined3d/device.c     2007-06-27 16:12:55.000000000 +0200
+++ wine/dlls/wined3d/device.c 2007-07-03 23:33:08.000000000 +0200
@@ -5340,17 +5340,19 @@
      *       NOTE: move code to surface to accomplish this
       ****************************************/
     IWineD3DSurfaceImpl *pSrcSurface  = (IWineD3DSurfaceImpl *)pSourceSurface;
+    IWineD3DSurfaceImpl *pDestSurface  = (IWineD3DSurfaceImpl*)pDestinationSurface;
     int srcWidth, srcHeight;
     unsigned int  srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
     WINED3DFORMAT destFormat, srcFormat;
-    UINT          destSize;
-    int srcLeft, destLeft, destTop;
+    int srcLeft, srcTop, destLeft, destTop;
     WINED3DPOOL       srcPool, destPool;
     int offset    = 0;
     int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
-    glDescriptor *glDescription = NULL;
+    glDescriptor *glDescription = NULL, *glSrcDescription = NULL;
     GLenum dummy;
     int bpp;
+    UINT destByteSize = 0, srcByteSize = 0;
+    int destPixelByteSize = 0, srcPixelByteSize = 0;
     CONVERT_TYPES convert = NO_CONVERSION;
 
     WINED3DSURFACE_DESC  winedesc;
@@ -5361,6 +5363,7 @@
     winedesc.Height = &srcSurfaceHeight;
     winedesc.Pool   = &srcPool;
     winedesc.Format = &srcFormat;
+    winedesc.Size   = &srcByteSize;
 
     IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
 
@@ -5368,7 +5371,7 @@
     winedesc.Height = &destSurfaceHeight;
     winedesc.Pool   = &destPool;
     winedesc.Format = &destFormat;
-    winedesc.Size   = &destSize;
+    winedesc.Size   = &destByteSize;
 
     IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
 
@@ -5381,13 +5384,9 @@
      * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
      * copy in sysmem and use regular surface loading.
      */
-    d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
-                    &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
+    d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
     if(convert != NO_CONVERSION) {
-        return IWineD3DSurface_BltFast(pDestinationSurface,
-                                        pDestPoint  ? pDestPoint->x : 0,
-                                        pDestPoint  ? pDestPoint->y : 0,
-                                        pSourceSurface, (RECT *) pSourceRect, 0);
+        return IWineD3DSurface_BltFast(pDestinationSurface, pDestPoint  ? pDestPoint->x : 0, pDestPoint  ? pDestPoint->y : 0, pSourceSurface, (RECT *) pSourceRect, 0);
     }
 
     if (destFormat == WINED3DFMT_UNKNOWN) {
@@ -5409,40 +5408,49 @@
 
     /* Make sure the surface is loaded and up to date */
     IWineD3DSurface_PreLoad(pDestinationSurface);
-
     IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
+    IWineD3DSurface_GetGlDesc(pDestinationSurface, &glSrcDescription);
 
     /* this needs to be done in lines if the sourceRect != the sourceWidth */
-    srcWidth   = pSourceRect ? pSourceRect->right - pSourceRect->left   : srcSurfaceWidth;
-    srcHeight  = pSourceRect ? pSourceRect->bottom - pSourceRect->top   : srcSurfaceHeight;
-    srcLeft    = pSourceRect ? pSourceRect->left : 0;
-    destLeft   = pDestPoint  ? pDestPoint->x : 0;
-    destTop    = pDestPoint  ? pDestPoint->y : 0;
-
-
-    /* This function doesn't support compressed textures
-    the pitch is just bytesPerPixel * width */
-    if(srcWidth != srcSurfaceWidth  || srcLeft ){
-        rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
-        offset   += srcLeft * pSrcSurface->bytesPerPixel;
-        /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
-    }
-    /* TODO DXT formats */
-
-    if(pSourceRect != NULL && pSourceRect->top != 0){
-       offset +=  pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
-    }
-    TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
-    ,This
-    ,glDescription->level
-    ,destLeft
-    ,destTop
-    ,srcWidth
-    ,srcHeight
-    ,glDescription->glFormat
-    ,glDescription->glType
-    ,IWineD3DSurface_GetData(pSourceSurface)
-    );
+    srcWidth    = pSourceRect    ? pSourceRect->right - pSourceRect->left    : srcSurfaceWidth;
+    srcHeight    = pSourceRect    ? pSourceRect->bottom - pSourceRect->top    : srcSurfaceHeight;
+    srcLeft        = pSourceRect    ? pSourceRect->left : 0;
+    srcTop        = pSourceRect    ? pSourceRect->top : 0;
+    destLeft    = pDestPoint    ? pDestPoint->x : 0;
+    destTop        = pDestPoint    ? pDestPoint->y : 0;
+
+    // Calculate the rowOffset / offset values, for copying
+    #define ISDXTFORMAT(format) \
+        (format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)
+
+    // Calculating this for our selves because I don't have faith in how surface->bytesPerPixel is calculated...
+    destPixelByteSize = destByteSize / (int)(destSurfaceWidth * destSurfaceHeight);
+    srcPixelByteSize = srcByteSize / (int)(srcSurfaceWidth * srcSurfaceHeight);
+
+    if(pSourceRect != NULL)
+    {
+        // Irregular surface formats
+        if (destFormat != srcFormat) {
+            FIXME("Can not convert between surface pixel formats...");
+
+            // Would require some relatively big code restructuring for rare occurances (that shouldn't even be supported?)
+
+            return WINED3DERR_INVALIDCALL;
+        }
+        // Uniform surface formats
+        else
+        {
+            if(srcWidth != srcSurfaceWidth || srcLeft > 0)
+            {
+                rowoffset = srcSurfaceWidth * srcPixelByteSize;
+                offset += (srcLeft * srcPixelByteSize);
+            }
+
+            if(srcTop > 0)
+               offset += srcTop * srcSurfaceWidth * srcPixelByteSize;
+        }
+
+    }
 
     /* Sanity check */
     if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
@@ -5452,70 +5460,203 @@
     }
 
     /* TODO: Cube and volume support */
-    if(rowoffset != 0){
-        /* not a whole row so we have to do it a line at a time */
-        int j;
-
-        /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
-        const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
-
-        for(j = destTop ; j < (srcHeight + destTop) ; j++){
-
-                glTexSubImage2D(glDescription->target
-                    ,glDescription->level
-                    ,destLeft
-                    ,j
-                    ,srcWidth
-                    ,1
-                    ,glDescription->glFormat
-                    ,glDescription->glType
-                    ,data /* could be quicker using */
-                );
-            data += rowoffset;
-        }
-
-    } else { /* Full width, so just write out the whole texture */
-
-        if (WINED3DFMT_DXT1 == destFormat ||
-            WINED3DFMT_DXT2 == destFormat ||
-            WINED3DFMT_DXT3 == destFormat ||
-            WINED3DFMT_DXT4 == destFormat ||
-            WINED3DFMT_DXT5 == destFormat) {
-            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
-                if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
-                    /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
-                    FIXME("Updating part of a compressed texture is not supported at the moment\n");
-                } if (destFormat != srcFormat) {
-                    FIXME("Updating mixed format compressed texture is not curretly support\n");
+    if(rowoffset != 0) {
+        // Compressed texture
+        if (ISDXTFORMAT(destFormat))
+        {
+            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC))
+            {
+#if 0
+                RECT rect;
+                rect.left = destLeft;
+                rect.top = destTop;
+                rect.right = destLeft + srcWidth;
+                rect.bottom = destTop + srcHeight;
+
+                // Lock source/destination regions
+                WINED3DLOCKED_RECT destRect, srcRect;
+
+                printf("Locking surfaces...\n");
+                if(FAILED(IWineD3DSurface_LockRect(pDestinationSurface, &destRect, &rect, 0)) || FAILED(IWineD3DSurface_LockRect(pSourceSurface, &srcRect, pSourceRect, WINED3DLOCK_READONLY)))
+                {
+                    // How should we handle this case?  Just returning an invalid call for now...
+                    return WINED3DERR_INVALIDCALL;
+                }
+
+                printf("Surfaces locked, copying contents now... ");
+                if(destFormat == WINED3DFMT_DXT1) {
+                    printf("DXT1\n");
+                    //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2));
+                    //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2));
+                    memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 8);
                 } else {
-                    GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
-                                                        glDescription->level,
-                                                        glDescription->glFormatInternal,
-                                                        srcWidth,
-                                                        srcHeight,
-                                                        0,
-                                                        destSize,
-                                                        IWineD3DSurface_GetData(pSourceSurface));
+                    printf("DXT2-5\n");
+                    //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 4));
+                    memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 16);
                 }
-            } else {
-                FIXME("Attempting to update a DXT compressed texture without hardware support\n");
+
+                // Unlock source/destination regions
+                IWineD3DSurface_UnlockRect(pSourceSurface);
+                IWineD3DSurface_UnlockRect(pDestinationSurface);
+                printf("Unlocking surfaces...\n");
+#elif 0
+                // Get pointers to the source/destination buffers
+                unsigned char *dest_data = (unsigned char*)IWineD3DSurface_GetData(pDestinationSurface);
+                const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);
+
+                // Copy subsection of source buffer, in to destination buffer.
+                unsigned char *dest_ptr = dest_data + offset;
+                const unsigned char *src_ptr = src_data + offset;
+
+                size_t i;
+                for(i = 0; i < srcHeight; ++i) {
+                    memcpy(dest_ptr, src_ptr, srcWidth * srcPixelByteSize);
+
+                    dest_ptr += rowoffset;
+                    src_ptr += rowoffset;
+                }
+
+
+                // Upload destination buffer to server
+                GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target,
+                                                    glDescription->level,
+                                                    glDescription->glFormatInternal,
+                                                    srcWidth,
+                                                    srcHeight,
+                                                    0,
+                                                    destByteSize,
+                                                    dest_data));
+
+                checkGLcall("glCompressedTexImage2DARB");
+#elif 1
+                int blocksize = 16;
+                if(destFormat == WINED3DFMT_DXT1)
+                    blocksize = 8;
+
+                #define max(a, b) (a > b? a : b)
+                srcHeight = max(srcHeight, 4);
+                srcWidth = max(srcWidth, 4);
+                #undef max
+
+                int data_size = (srcWidth / 4) * (srcHeight / 4) * blocksize;
+                int row_size = data_size / srcHeight;
+                int pixel_size = row_size / srcWidth;
+                int stride = srcSurfaceWidth * pixel_size;
+
+                unsigned char *temp_buffer = HeapAlloc(GetProcessHeap(), 0, data_size);
+                unsigned char *temp_ptr = temp_buffer;
+
+                // Debug info
+                //printf(" > BytesTotal: %i | BytesPerPixel: %i | RowSize: %i\n", data_size, pixel_size, row_size);
+                //printf(" > Source: %i -> %i, %i -> %i | Dest: %i, %i\n", srcLeft, srcWidth, srcTop, srcHeight, destLeft, destTop);
+                //printf(" > Offset: %i\n", (int)((row_size * srcTop) + srcLeft * pixel_size));
+
+                // Get pointers to the source buffer
+                const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);
+                src_data += (stride * srcTop) + srcLeft * pixel_size;
+
+                size_t i;
+                for(i = 0; i < srcHeight; ++i) {
+                    memcpy(temp_ptr, src_data, row_size);
+                    temp_ptr += row_size;
+                    src_data += stride;
+                }
+
+                GL_EXTCALL(glCompressedTexSubImage2DARB(
+                    glDescription->target,
+                    glDescription->level,
+                    destLeft,
+                    destTop,
+                    srcWidth,
+                    srcHeight,
+                    glDescription->glFormatInternal,
+                    data_size,
+                    temp_buffer
+                ));
+                //checkGLcall("glCompressedTexSubImage2DARB");
+
+                HeapFree(GetProcessHeap(), 0, temp_buffer);
+#endif
             }
+            else
+            {
+                FIXME("TODO: Need to update a DXT compressed texture without hardware support\n");
+            }
+        }
+        // Uncompressed texture
+        else
+        {
+            /* not a whole row so we have to do it a line at a time */
+            int j;
 
+            /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
+            const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
 
-        } else {
-            glTexSubImage2D(glDescription->target
-                    ,glDescription->level
-                    ,destLeft
-                    ,destTop
-                    ,srcWidth
-                    ,srcHeight
-                    ,glDescription->glFormat
-                    ,glDescription->glType
-                    ,IWineD3DSurface_GetData(pSourceSurface)
-                );
+            for(j = destTop; j < (srcHeight + destTop); ++j)
+            {
+                    glTexSubImage2D(glDescription->target
+                        ,glDescription->level
+                        ,destLeft
+                        ,j
+                        ,srcWidth
+                        ,1
+                        ,glDescription->glFormat
+                        ,glDescription->glType
+                        ,data /* could be quicker using */
+                    );
+                data += rowoffset;
+            }
+        }
+    } else {
+        // Compressed texture
+        if (ISDXTFORMAT(destFormat))
+        {
+            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC))
+            {
+                int blocksize = 16;
+                if(destFormat == WINED3DFMT_DXT1)
+                    blocksize = 8;
+
+                #define max(a, b) (a > b? a : b)
+                int data_size = (max(srcWidth, 4) / 4) * (max(srcHeight, 4) / 4) * blocksize;
+                #undef max
+
+                //printf(" -> S = %i | CompressedTexImage2D(?, %i, %i, %i, %i, 0, %i, ?)\n", destByteSize, glDescription->level, glDescription->glFormatInternal, srcWidth, srcHeight, data_size);
+		GL_EXTCALL(glCompressedTexSubImage2DARB(glDescription->target,
+                                                    glDescription->level,
+                                                    destLeft,
+                                                    destTop,
+                                                    srcWidth,
+                                                    srcHeight,
+                                                    glDescription->glFormatInternal,
+                                                    data_size,
+                                                    IWineD3DSurface_GetData(pSourceSurface)));
+
+                checkGLcall("glCompressedTexImage2DARB");
+            }
+            else
+            {
+                FIXME("TODO: Need to update a DXT compressed texture without hardware support\n");
+            }
+        }
+        // Uncompressed Texture
+        else
+        {
+            glTexSubImage2D(
+                glDescription->target,
+                glDescription->level,
+                destLeft,
+                destTop,
+                srcWidth,
+                srcHeight,
+                glDescription->glFormat,
+                glDescription->glType,
+                IWineD3DSurface_GetData(pSourceSurface)
+            );
+
+            checkGLcall("glTexSubImage2D");
         }
      }
-    checkGLcall("glTexSubImage2D");
 
     LEAVE_GL();
 


Reply via email to