예제 #1
0
파일: resource.c 프로젝트: zalcyon/wine
void *wined3d_resource_map_internal(struct wined3d_resource *resource, DWORD flags)
{
    struct wined3d_device *device = resource->device;
    struct wined3d_context *context = NULL;
    void *mem;

    if (device->d3d_initialized)
        context = context_acquire(device, NULL);

    if (!wined3d_resource_prepare_map_memory(resource, context))
    {
        WARN("Out of memory.\n");
        context_release(context);
        return NULL;
    }

    if (flags & WINED3D_MAP_DISCARD)
    {
        switch (resource->map_binding)
        {
            case WINED3D_LOCATION_BUFFER:
                resource->map_buffer = wined3d_device_get_bo(device, resource->size,
                        GL_STREAM_DRAW_ARB, GL_PIXEL_UNPACK_BUFFER_ARB, context);
                break;

            case WINED3D_LOCATION_SYSMEM:
                wined3d_resource_allocate_sysmem(resource);
                break;

            default:
                if (resource->access_fence)
                    ERR("Location %s does not support DISCARD maps.\n",
                            wined3d_debug_location(resource->map_binding));
                if (resource->pool != WINED3D_POOL_DEFAULT)
                    FIXME("Discard used on %s pool resource.\n", debug_d3dpool(resource->pool));
        }
        wined3d_resource_validate_location(resource, resource->map_binding);
    }
    else
    {
        wined3d_resource_load_location(resource, context, resource->map_binding);
    }

    mem = wined3d_resource_get_map_ptr(resource, context, flags);

    if (context)
        context_release(context);

    return mem;
}
예제 #2
0
파일: swapchain.c 프로젝트: Dimillian/wine
static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device,
        struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops)
{
    const struct wined3d_adapter *adapter = device->adapter;
    struct wined3d_resource_desc surface_desc;
    BOOL displaymode_set = FALSE;
    RECT client_rect;
    HWND window;
    HRESULT hr;
    UINT i;

    if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX)
    {
        FIXME("The application requested %u back buffers, this is not supported.\n",
                desc->backbuffer_count);
        return WINED3DERR_INVALIDCALL;
    }

    if (desc->backbuffer_count > 1)
    {
        FIXME("The application requested more than one back buffer, this is not properly supported.\n"
                "Please configure the application to use double buffering (1 back buffer) if possible.\n");
    }

    if (device->wined3d->flags & WINED3D_NO3D)
        swapchain->swapchain_ops = &swapchain_gdi_ops;
    else
        swapchain->swapchain_ops = &swapchain_gl_ops;

    window = desc->device_window ? desc->device_window : device->create_parms.focus_window;

    swapchain->device = device;
    swapchain->parent = parent;
    swapchain->parent_ops = parent_ops;
    swapchain->ref = 1;
    swapchain->win_handle = window;
    swapchain->device_window = window;

    if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d,
            adapter->ordinal, &swapchain->original_mode, NULL)))
    {
        ERR("Failed to get current display mode, hr %#x.\n", hr);
        goto err;
    }

    GetClientRect(window, &client_rect);
    if (desc->windowed
            && (!desc->backbuffer_width || !desc->backbuffer_height
            || desc->backbuffer_format == WINED3DFMT_UNKNOWN))
    {

        if (!desc->backbuffer_width)
        {
            desc->backbuffer_width = client_rect.right;
            TRACE("Updating width to %u.\n", desc->backbuffer_width);
        }

        if (!desc->backbuffer_height)
        {
            desc->backbuffer_height = client_rect.bottom;
            TRACE("Updating height to %u.\n", desc->backbuffer_height);
        }

        if (desc->backbuffer_format == WINED3DFMT_UNKNOWN)
        {
            desc->backbuffer_format = swapchain->original_mode.format_id;
            TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->original_mode.format_id));
        }
    }
    swapchain->desc = *desc;
    swapchain_update_render_to_fbo(swapchain);

    TRACE("Creating front buffer.\n");

    surface_desc.resource_type = WINED3D_RTYPE_SURFACE;
    surface_desc.format = swapchain->desc.backbuffer_format;
    surface_desc.multisample_type = swapchain->desc.multisample_type;
    surface_desc.multisample_quality = swapchain->desc.multisample_quality;
    surface_desc.usage = 0;
    surface_desc.pool = WINED3D_POOL_DEFAULT;
    surface_desc.width = swapchain->desc.backbuffer_width;
    surface_desc.height = swapchain->desc.backbuffer_height;
    surface_desc.depth = 1;
    surface_desc.size = 0;

    if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent,
            parent, &surface_desc, &swapchain->front_buffer)))
    {
        WARN("Failed to create front buffer, hr %#x.\n", hr);
        goto err;
    }

    surface_set_swapchain(swapchain->front_buffer, swapchain);
    if (!(device->wined3d->flags & WINED3D_NO3D))
    {
        wined3d_resource_validate_location(&swapchain->front_buffer->resource, WINED3D_LOCATION_DRAWABLE);
        wined3d_resource_invalidate_location(&swapchain->front_buffer->resource, ~WINED3D_LOCATION_DRAWABLE);
    }

    /* MSDN says we're only allowed a single fullscreen swapchain per device,
     * so we should really check to see if there is a fullscreen swapchain
     * already. Does a single head count as full screen? */

    if (!desc->windowed)
    {
        struct wined3d_display_mode mode;

        /* Change the display settings */
        mode.width = desc->backbuffer_width;
        mode.height = desc->backbuffer_height;
        mode.format_id = desc->backbuffer_format;
        mode.refresh_rate = desc->refresh_rate;
        mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;

        if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &mode)))
        {
            WARN("Failed to set display mode, hr %#x.\n", hr);
            goto err;
        }
        displaymode_set = TRUE;
    }

    if (!(device->wined3d->flags & WINED3D_NO3D))
    {
        hr = wined3d_cs_emit_create_swapchain_context(device->cs, swapchain);
        if (FAILED(hr))
            goto err;
    }

    if (swapchain->desc.backbuffer_count > 0)
    {
        swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0,
                sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count);
        if (!swapchain->back_buffers)
        {
            ERR("Failed to allocate backbuffer array memory.\n");
            hr = E_OUTOFMEMORY;
            goto err;
        }

        surface_desc.usage |= WINED3DUSAGE_RENDERTARGET;
        for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
        {
            TRACE("Creating back buffer %u.\n", i);
            if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent,
                    parent, &surface_desc, &swapchain->back_buffers[i])))
            {
                WARN("Failed to create back buffer %u, hr %#x.\n", i, hr);
                swapchain->desc.backbuffer_count = i;
                goto err;
            }
            surface_set_swapchain(swapchain->back_buffers[i], swapchain);
        }
    }

    /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */
    if (desc->enable_auto_depth_stencil && !(device->wined3d->flags & WINED3D_NO3D))
    {
        TRACE("Creating depth/stencil buffer.\n");
        if (!device->auto_depth_stencil)
        {
            surface_desc.format = swapchain->desc.auto_depth_stencil_format;
            surface_desc.usage = WINED3DUSAGE_DEPTHSTENCIL;

            if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent,
                    device->device_parent, &surface_desc, &device->auto_depth_stencil)))
            {
                WARN("Failed to create the auto depth stencil, hr %#x.\n", hr);
                goto err;
            }
        }
    }

    wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma);

    return WINED3D_OK;

err:
    if (displaymode_set)
    {
        if (FAILED(wined3d_set_adapter_display_mode(device->wined3d,
                adapter->ordinal, &swapchain->original_mode)))
            ERR("Failed to restore display mode.\n");
        ClipCursor(NULL);
    }

    if (swapchain->back_buffers)
    {
        for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
        {
            if (swapchain->back_buffers[i])
            {
                surface_set_swapchain(swapchain->back_buffers[i], NULL);
                wined3d_surface_decref(swapchain->back_buffers[i]);
            }
        }
        HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
    }

    if (swapchain->context)
    {
        if (swapchain->context[0])
        {
            context_release(swapchain->context[0]);
            context_destroy(device, swapchain->context[0]);
            swapchain->num_contexts = 0;
        }
        HeapFree(GetProcessHeap(), 0, swapchain->context);
    }

    if (swapchain->front_buffer)
    {
        surface_set_swapchain(swapchain->front_buffer, NULL);
        wined3d_surface_decref(swapchain->front_buffer);
    }

    return hr;
}
예제 #3
0
파일: swapchain.c 프로젝트: Dimillian/wine
static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in,
        const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags,
        struct wined3d_surface *depth_stencil)
{
    struct wined3d_surface *back_buffer = swapchain->back_buffers[0];
    const struct wined3d_gl_info *gl_info;
    struct wined3d_context *context;
    RECT src_rect, dst_rect;
    BOOL render_to_fbo;

    context = context_acquire(swapchain->device, back_buffer);
    if (!context->valid)
    {
        context_release(context);
        WARN("Invalid context, skipping present.\n");
        return;
    }

    gl_info = context->gl_info;

    if (swapchain->device->logo_texture)
    {
        struct wined3d_surface *src_surface = surface_from_resource(
                wined3d_texture_get_sub_resource(swapchain->device->logo_texture, 0));
        RECT rect = {0, 0, src_surface->resource.width, src_surface->resource.height};

        /* Blit the logo into the upper left corner of the drawable. */
        wined3d_surface_blt(back_buffer, &rect, src_surface, &rect, WINEDDBLT_ALPHATEST,
                NULL, WINED3D_TEXF_POINT);
    }

    TRACE("Presenting HDC %p.\n", context->hdc);

    render_to_fbo = swapchain->render_to_fbo;

    if (src_rect_in)
    {
        src_rect = *src_rect_in;
        if (!render_to_fbo && (src_rect.left || src_rect.top
                || src_rect.right != swapchain->desc.backbuffer_width
                || src_rect.bottom != swapchain->desc.backbuffer_height))
        {
            render_to_fbo = TRUE;
        }
    }
    else
    {
        src_rect.left = 0;
        src_rect.top = 0;
        src_rect.right = swapchain->desc.backbuffer_width;
        src_rect.bottom = swapchain->desc.backbuffer_height;
    }

    if (dst_rect_in)
        dst_rect = *dst_rect_in;
    else
        GetClientRect(swapchain->win_handle, &dst_rect);

    if (!render_to_fbo && (dst_rect.left || dst_rect.top
            || dst_rect.right != swapchain->desc.backbuffer_width
            || dst_rect.bottom != swapchain->desc.backbuffer_height))
        render_to_fbo = TRUE;

    /* Rendering to a window of different size, presenting partial rectangles,
     * or rendering to a different window needs help from FBO_blit or a textured
     * draw. Render the swapchain to a FBO in the future.
     *
     * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve
     * all these issues - this fails if the window is smaller than the backbuffer.
     */
    if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO)
    {
        wined3d_resource_load_location(&back_buffer->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
        wined3d_resource_invalidate_location(&back_buffer->resource, WINED3D_LOCATION_DRAWABLE);
        swapchain->render_to_fbo = TRUE;
        swapchain_update_draw_bindings(swapchain);
    }
    else
    {
        wined3d_resource_load_location(&back_buffer->resource, context, back_buffer->draw_binding);
    }

    if (swapchain->render_to_fbo)
    {
        static unsigned int once;

        if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP && !once++)
            FIXME("WINED3D_SWAP_EFFECT_FLIP not implemented.\n");

        swapchain_blit(swapchain, context, &src_rect, &dst_rect);
    }

    if (swapchain->num_contexts > 1 && !wined3d_settings.cs_multithreaded)
        gl_info->gl_ops.gl.p_glFlush();

    /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */
    gl_info->gl_ops.wgl.p_wglSwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */

    TRACE("SwapBuffers called, Starting new frame\n");
    /* FPS support */
    if (TRACE_ON(fps))
    {
        DWORD time = GetTickCount();
        ++swapchain->frames;

        /* every 1.5 seconds */
        if (time - swapchain->prev_time > 1500)
        {
            TRACE_(fps)("%p @ approx %.2ffps\n",
                    swapchain, 1000.0 * swapchain->frames / (time - swapchain->prev_time));
            swapchain->prev_time = time;
            swapchain->frames = 0;
        }
    }

    wined3d_resource_validate_location(&swapchain->front_buffer->resource, WINED3D_LOCATION_DRAWABLE);
    wined3d_resource_invalidate_location(&swapchain->front_buffer->resource, ~WINED3D_LOCATION_DRAWABLE);
    switch (swapchain->desc.swap_effect)
    {
        case WINED3D_SWAP_EFFECT_DISCARD:
            wined3d_resource_validate_location(&back_buffer->resource, WINED3D_LOCATION_DISCARDED);
            break;

        case WINED3D_SWAP_EFFECT_FLIP:
            wined3d_resource_validate_location(&back_buffer->resource, back_buffer->draw_binding);
            wined3d_resource_invalidate_location(&back_buffer->resource, ~back_buffer->draw_binding);
            break;

        default:
            break;
    }

    if (depth_stencil)
    {
        if (swapchain->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
                || depth_stencil->flags & SFLAG_DISCARD)
        {
            surface_modify_ds_location(depth_stencil, WINED3D_LOCATION_DISCARDED,
                    depth_stencil->resource.width,
                    depth_stencil->resource.height);
            if (depth_stencil == swapchain->device->cs->onscreen_depth_stencil)
            {
                wined3d_surface_decref(swapchain->device->cs->onscreen_depth_stencil);
                swapchain->device->cs->onscreen_depth_stencil = NULL;
            }
        }
    }

    context_release(context);
}