Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}