Esempio n. 1
0
/* Routine common to the draw primitive and draw indexed primitive routines */
void drawPrimitive(IWineD3DDeviceImpl *device, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData)
{
    const struct wined3d_state *state = &device->stateBlock->state;
    struct wined3d_context *context;
    unsigned int i;

    if (!index_count) return;

    if (state->render_states[WINED3DRS_COLORWRITEENABLE])
    {
        /* Invalidate the back buffer memory so LockRect will read it the next time */
        for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
        {
            IWineD3DSurfaceImpl *target = device->render_targets[i];
            if (target)
            {
                surface_load_location(target, SFLAG_INDRAWABLE, NULL);
                surface_modify_location(target, SFLAG_INDRAWABLE, TRUE);
            }
        }
    }

    /* Signals other modules that a drawing is in progress and the stateblock finalized */
    device->isInDraw = TRUE;

    context = context_acquire(device, device->render_targets[0]);
    if (!context->valid)
    {
        context_release(context);
        WARN("Invalid context, skipping draw.\n");
        return;
    }

    context_apply_draw_state(context, device);

    if (device->depth_stencil)
    {
        /* Note that this depends on the context_acquire() call above to set
         * context->render_offscreen properly. We don't currently take the
         * Z-compare function into account, but we could skip loading the
         * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note
         * that we never copy the stencil data.*/
        DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
        if (state->render_states[WINED3DRS_ZWRITEENABLE] || state->render_states[WINED3DRS_ZENABLE])
        {
            IWineD3DSurfaceImpl *ds = device->depth_stencil;
            RECT current_rect, draw_rect, r;

            if (location == SFLAG_DS_ONSCREEN && ds != device->onscreen_depth_stencil)
                device_switch_onscreen_ds(device, context, ds);

            if (ds->flags & location)
                SetRect(&current_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy);
            else
                SetRectEmpty(&current_rect);

            device_get_draw_rect(device, &draw_rect);

            IntersectRect(&r, &draw_rect, &current_rect);
            if (!EqualRect(&r, &draw_rect))
                surface_load_ds_location(ds, context, location);

            if (state->render_states[WINED3DRS_ZWRITEENABLE])
            {
                surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
                surface_modify_location(ds, SFLAG_INDRAWABLE, TRUE);
            }
        }
    }

    if ((!context->gl_info->supported[WINED3D_GL_VERSION_2_0]
            || (!glPointParameteri && !context->gl_info->supported[NV_POINT_SPRITE]))
            && context->render_offscreen
            && state->render_states[WINED3DRS_POINTSPRITEENABLE]
            && state->gl_primitive_type == GL_POINTS)
    {
        FIXME("Point sprite coordinate origin switching not supported.\n");
    }

    /* Ok, we will be updating the screen from here onwards so grab the lock */
    ENTER_GL();
    {
        GLenum glPrimType = state->gl_primitive_type;
        BOOL emulation = FALSE;
        const struct wined3d_stream_info *stream_info = &device->strided_streams;
        struct wined3d_stream_info stridedlcl;

        if (!use_vs(state))
        {
            if (!stream_info->position_transformed && context->num_untracked_materials
                    && state->render_states[WINED3DRS_LIGHTING])
            {
                static BOOL warned;
                if (!warned) {
                    FIXME("Using software emulation because not all material properties could be tracked\n");
                    warned = TRUE;
                } else {
                    TRACE("Using software emulation because not all material properties could be tracked\n");
                }
                emulation = TRUE;
            }
            else if (context->fog_coord && state->render_states[WINED3DRS_FOGENABLE])
            {
                /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte
                 * to a float in the vertex buffer
                 */
                static BOOL warned;
                if (!warned) {
                    FIXME("Using software emulation because manual fog coordinates are provided\n");
                    warned = TRUE;
                } else {
                    TRACE("Using software emulation because manual fog coordinates are provided\n");
                }
                emulation = TRUE;
            }

            if(emulation) {
                stream_info = &stridedlcl;
                memcpy(&stridedlcl, &device->strided_streams, sizeof(stridedlcl));
                remove_vbos(context->gl_info, state, &stridedlcl);
            }
        }

        if (device->useDrawStridedSlow || emulation)
        {
            /* Immediate mode drawing */
            if (use_vs(state))
            {
                static BOOL warned;
                if (!warned) {
                    FIXME("Using immediate mode with vertex shaders for half float emulation\n");
                    warned = TRUE;
                } else {
                    TRACE("Using immediate mode with vertex shaders for half float emulation\n");
                }
                drawStridedSlowVs(context->gl_info, state, stream_info,
                                  index_count, glPrimType, idxData, idxSize, StartIdx);
            }
            else
            {
                drawStridedSlow(device, context, stream_info, index_count,
                                glPrimType, idxData, idxSize, StartIdx);
            }
        }
        else if (device->instancedDraw)
        {
            /* Instancing emulation with mixing immediate mode and arrays */
            drawStridedInstanced(context->gl_info, state, stream_info,
                                 index_count, glPrimType, idxData, idxSize, StartIdx);
        }
        else
        {
            drawStridedFast(glPrimType, index_count, idxSize, idxData, StartIdx);
        }
    }

    /* Finished updating the screen, restore lock */
    LEAVE_GL();

    for(i = 0; i < device->num_buffer_queries; ++i)
    {
        wined3d_event_query_issue(device->buffer_queries[i], device);
    }

    if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */

    context_release(context);

    TRACE("Done all gl drawing\n");

    /* Control goes back to the device, stateblock values may change again */
    device->isInDraw = FALSE;
}
Esempio n. 2
0
/* Routine common to the draw primitive and draw indexed primitive routines */
void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData)
{

    IWineD3DDeviceImpl           *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DSurfaceImpl          *target;
    struct wined3d_context *context;
    unsigned int i;

    if (!index_count) return;

    if (This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE])
    {
        /* Invalidate the back buffer memory so LockRect will read it the next time */
        for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
        {
            target = (IWineD3DSurfaceImpl *)This->render_targets[i];
            if (target)
            {
                IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
                IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
            }
        }
    }

    /* Signals other modules that a drawing is in progress and the stateblock finalized */
    This->isInDraw = TRUE;

    context = context_acquire(This, This->render_targets[0], CTXUSAGE_DRAWPRIM);
    if (!context->valid)
    {
        context_release(context);
        WARN("Invalid context, skipping draw.\n");
        return;
    }

#if defined(VBOX_WITH_WDDM)
    DBGL_CHECK_DRAWPRIM(context->gl_info, This);
#endif

    if (This->stencilBufferTarget) {
        /* Note that this depends on the context_acquire() call above to set
         * This->render_offscreen properly. We don't currently take the
         * Z-compare function into account, but we could skip loading the
         * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note
         * that we never copy the stencil data.*/
        DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
        if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE]
                || This->stateBlock->renderState[WINED3DRS_ZENABLE])
            surface_load_ds_location(This->stencilBufferTarget, context, location);
        if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE])
            surface_modify_ds_location(This->stencilBufferTarget, location);
    }

    /* Ok, we will be updating the screen from here onwards so grab the lock */
    ENTER_GL();
    {
        GLenum glPrimType = This->stateBlock->gl_primitive_type;
        BOOL emulation = FALSE;
        const struct wined3d_stream_info *stream_info = &This->strided_streams;
        struct wined3d_stream_info stridedlcl;

        if (!use_vs(This->stateBlock))
        {
            if (!This->strided_streams.position_transformed && context->num_untracked_materials
                    && This->stateBlock->renderState[WINED3DRS_LIGHTING])
            {
                static BOOL warned;
                if (!warned) {
                    FIXME("Using software emulation because not all material properties could be tracked\n");
                    warned = TRUE;
                } else {
                    TRACE("Using software emulation because not all material properties could be tracked\n");
                }
                emulation = TRUE;
            }
            else if (context->fog_coord && This->stateBlock->renderState[WINED3DRS_FOGENABLE])
            {
                /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte
                 * to a float in the vertex buffer
                 */
                static BOOL warned;
                if (!warned) {
                    FIXME("Using software emulation because manual fog coordinates are provided\n");
                    warned = TRUE;
                } else {
                    TRACE("Using software emulation because manual fog coordinates are provided\n");
                }
                emulation = TRUE;
            }

            if(emulation) {
                stream_info = &stridedlcl;
                memcpy(&stridedlcl, &This->strided_streams, sizeof(stridedlcl));
                remove_vbos(This, &stridedlcl);
            }
        }

        if (This->useDrawStridedSlow || emulation) {
            /* Immediate mode drawing */
            if (use_vs(This->stateBlock))
            {
                static BOOL warned;
                if (!warned) {
                    FIXME("Using immediate mode with vertex shaders for half float emulation\n");
                    warned = TRUE;
                } else {
                    TRACE("Using immediate mode with vertex shaders for half float emulation\n");
                }
                drawStridedSlowVs(iface, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx);
            } else {
                drawStridedSlow(iface, context, stream_info, index_count,
                        glPrimType, idxData, idxSize, StartIdx);
            }
        } else if(This->instancedDraw) {
            /* Instancing emulation with mixing immediate mode and arrays */
            drawStridedInstanced(iface, &This->strided_streams, index_count,
                    glPrimType, idxData, idxSize, StartIdx);
        } else {
            drawStridedFast(iface, glPrimType, index_count, idxSize, idxData, StartIdx);
        }
    }

    /* Finished updating the screen, restore lock */
    LEAVE_GL();

    for(i = 0; i < This->num_buffer_queries; i++)
    {
        wined3d_event_query_issue(This->buffer_queries[i], This);
    }

    if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */

    context_release(context);

    TRACE("Done all gl drawing\n");

    /* Diagnostics */
#ifdef SHOW_FRAME_MAKEUP
    {
        static long int primCounter = 0;
        /* NOTE: set primCounter to the value reported by drawprim
           before you want to to write frame makeup to /tmp */
        if (primCounter >= 0) {
            WINED3DLOCKED_RECT r;
            char buffer[80];
            IWineD3DSurface_LockRect(This->render_targets[0], &r, NULL, WINED3DLOCK_READONLY);
            sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter);
            TRACE("Saving screenshot %s\n", buffer);
            IWineD3DSurface_SaveSnapshot(This->render_targets[0], buffer);
            IWineD3DSurface_UnlockRect(This->render_targets[0]);

#ifdef SHOW_TEXTURE_MAKEUP
           {
            IWineD3DSurface *pSur;
            int textureNo;
            for (textureNo = 0; textureNo < MAX_COMBINED_SAMPLERS; ++textureNo) {
                if (This->stateBlock->textures[textureNo] != NULL) {
                    sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
                    TRACE("Saving texture %s\n", buffer);
                    if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
                            IWineD3DTexture_GetSurfaceLevel(This->stateBlock->textures[textureNo], 0, &pSur);
                            IWineD3DSurface_SaveSnapshot(pSur, buffer);
                            IWineD3DSurface_Release(pSur);
                    } else  {
                        FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
                    }
                }
            }
           }
#endif
        }
        TRACE("drawprim #%ld\n", primCounter);
        ++primCounter;
    }
#endif

    /* Control goes back to the device, stateblock values may change again */
    This->isInDraw = FALSE;
}
Esempio n. 3
0
HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels,
        IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool,
        IUnknown *parent, const struct wined3d_parent_ops *parent_ops
#ifdef VBOX_WITH_WDDM
        , HANDLE *shared_handle
        , void **pavClientMem
#endif
        )
{
    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
    const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info);
    UINT pow2_width, pow2_height;
    UINT tmp_w, tmp_h;
    unsigned int i;
    HRESULT hr;

    /* TODO: It should only be possible to create textures for formats
     * that are reported as supported. */
    if (WINED3DFMT_UNKNOWN >= format)
    {
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
        return WINED3DERR_INVALIDCALL;
    }

    /* Non-power2 support. */
    if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO])
    {
        pow2_width = width;
        pow2_height = height;
    }
    else
    {
        /* Find the nearest pow2 match. */
        pow2_width = pow2_height = 1;
        while (pow2_width < width) pow2_width <<= 1;
        while (pow2_height < height) pow2_height <<= 1;

        if (pow2_width != width || pow2_height != height)
        {
            if (levels > 1)
            {
                WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n");
                return WINED3DERR_INVALIDCALL;
            }
            levels = 1;
        }
    }

    /* Calculate levels for mip mapping. */
    if (usage & WINED3DUSAGE_AUTOGENMIPMAP)
    {
        if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
        {
            WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }

        if (levels > 1)
        {
            WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }

        levels = 1;
    }
    else if (!levels)
    {
        levels = wined3d_log2i(max(width, height)) + 1;
        TRACE("Calculated levels = %u.\n", levels);
    }

    texture->lpVtbl = &IWineD3DTexture_Vtbl;

    hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, levels, WINED3DRTYPE_TEXTURE,
            device, 0, usage, format_desc, pool, parent, parent_ops
#ifdef VBOX_WITH_WDDM
            , shared_handle, pavClientMem
#endif
        );
    if (FAILED(hr))
    {
        WARN("Failed to initialize basetexture, returning %#x.\n", hr);
        return hr;
    }

    /* Precalculated scaling for 'faked' non power of two texture coords.
     * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
     * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE
     * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */
    if (gl_info->supported[WINE_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height))
    {
        texture->baseTexture.pow2Matrix[0] = 1.0f;
        texture->baseTexture.pow2Matrix[5] = 1.0f;
        texture->baseTexture.pow2Matrix[10] = 1.0f;
        texture->baseTexture.pow2Matrix[15] = 1.0f;
        texture->target = GL_TEXTURE_2D;
        texture->cond_np2 = TRUE;
        texture->baseTexture.minMipLookup = minMipLookup_noFilter;
    }
    else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height)
            && !(format_desc->format == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE]
            && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
    {
        if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE;

        texture->baseTexture.pow2Matrix[0] = (float)width;
        texture->baseTexture.pow2Matrix[5] = (float)height;
        texture->baseTexture.pow2Matrix[10] = 1.0f;
        texture->baseTexture.pow2Matrix[15] = 1.0f;
        texture->target = GL_TEXTURE_RECTANGLE_ARB;
        texture->cond_np2 = TRUE;

        if(texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
        {
            texture->baseTexture.minMipLookup = minMipLookup_noMip;
        }
        else
        {
            texture->baseTexture.minMipLookup = minMipLookup_noFilter;
        }
    }
    else
    {
        if ((width != pow2_width) || (height != pow2_height))
        {
            texture->baseTexture.pow2Matrix_identity = FALSE;
            texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width));
            texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height));
        }
        else
        {
            texture->baseTexture.pow2Matrix[0] = 1.0f;
            texture->baseTexture.pow2Matrix[5] = 1.0f;
        }

        texture->baseTexture.pow2Matrix[10] = 1.0f;
        texture->baseTexture.pow2Matrix[15] = 1.0f;
        texture->target = GL_TEXTURE_2D;
        texture->cond_np2 = FALSE;
    }
    TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]);

    /* Generate all the surfaces. */
    tmp_w = width;
    tmp_h = height;
    for (i = 0; i < texture->baseTexture.levels; ++i)
    {
#ifdef VBOX_WITH_WDDM
        /* Use the callback to create the texture surface. */
        hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format,
                usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]
                , NULL /* <- we first create a surface in an everage "non-shared" fashion and initialize its share properties later (see below)
                        * this is done this way because the surface does not have its parent (texture) setup properly
                        * thus we can not initialize texture at this stage */
                , pavClientMem ? pavClientMem[i] : NULL);

#else
        /* Use the callback to create the texture surface. */
        hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format,
                usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]);
#endif

        if (FAILED(hr))
        {
            FIXME("Failed to create surface %p, hr %#x\n", texture, hr);
            texture->surfaces[i] = NULL;
            texture_cleanup(texture);
            return hr;
        }

        IWineD3DSurface_SetContainer(texture->surfaces[i], (IWineD3DBase *)texture);
        TRACE("Created surface level %u @ %p.\n", i, texture->surfaces[i]);
        surface_set_texture_target(texture->surfaces[i], texture->target);
        /* Calculate the next mipmap level. */
        tmp_w = max(1, tmp_w >> 1);
        tmp_h = max(1, tmp_h >> 1);
    }
    texture->baseTexture.internal_preload = texture_internal_preload;

#ifdef VBOX_WITH_WDDM
    if (VBOXSHRC_IS_SHARED(texture))
    {
        Assert(shared_handle);
        for (i = 0; i < texture->baseTexture.levels; ++i)
        {
            VBOXSHRC_COPY_SHAREDATA((IWineD3DSurfaceImpl*)texture->surfaces[i], texture);
        }
#ifdef DEBUG
        for (i = 0; i < texture->baseTexture.levels; ++i)
        {
            Assert(!((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name);
        }
#endif
        for (i = 0; i < texture->baseTexture.levels; ++i)
        {
            if (!VBOXSHRC_IS_SHARED_OPENED(texture))
            {
                IWineD3DSurface_LoadLocation(texture->surfaces[i], SFLAG_INTEXTURE, NULL);
                Assert(!(*shared_handle));
                *shared_handle = VBOXSHRC_GET_SHAREHANDLE(texture);
            }
            else
            {
                surface_setup_location_onopen((IWineD3DSurfaceImpl*)texture->surfaces[i]);
                Assert(*shared_handle);
                Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(texture));
            }
        }
#ifdef DEBUG
        for (i = 0; i < texture->baseTexture.levels; ++i)
        {
            Assert((GLuint)(*shared_handle) == ((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name);
        }
#endif

        if (!VBOXSHRC_IS_SHARED_OPENED(texture))
        {
            struct wined3d_context * context;

            Assert(!device->isInDraw);

            /* flush to ensure the texture is allocated before it is used by another
             * process opening it */
            context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
            if (context->valid)
            {
                wglFlush();
            }
            else
            {
                ERR("invalid context!");
            }
            context_release(context);
        }
    }
    else
    {
        Assert(!shared_handle);
    }
#endif

    return WINED3D_OK;
}