summaryrefslogtreecommitdiffstats
path: root/vcl/skia/x11/gdiimpl.cxx
blob: 1602218c16ac85aa14adefeb15eb4a76c88987a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Some of this code is based on Skia source code, covered by the following
 * license notice (see readlicense_oo for the full license):
 *
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 */

#include <skia/x11/gdiimpl.hxx>

#include <tools/sk_app/unix/WindowContextFactory_unix.h>

#include <skia/utils.hxx>
#include <skia/zone.hxx>

#include <X11/Xutil.h>

X11SkiaSalGraphicsImpl::X11SkiaSalGraphicsImpl(X11SalGraphics& rParent)
    : SkiaSalGraphicsImpl(rParent, rParent.GetGeometryProvider())
    , mX11Parent(rParent)
{
}

X11SkiaSalGraphicsImpl::~X11SkiaSalGraphicsImpl() {}

void X11SkiaSalGraphicsImpl::Init()
{
    // The m_pFrame and m_pVDev pointers are updated late in X11
    setProvider(mX11Parent.GetGeometryProvider());
    SkiaSalGraphicsImpl::Init();
}

void X11SkiaSalGraphicsImpl::createWindowContext(bool forceRaster)
{
    assert(mX11Parent.GetDrawable() != None);
    mWindowContext = createWindowContext(
        mX11Parent.GetXDisplay(), mX11Parent.GetDrawable(), &mX11Parent.GetVisual(), GetWidth(),
        GetHeight(), forceRaster ? SkiaHelper::RenderRaster : SkiaHelper::renderMethodToUse(),
        false);
}

std::unique_ptr<sk_app::WindowContext>
X11SkiaSalGraphicsImpl::createWindowContext(Display* display, Drawable drawable,
                                            const XVisualInfo* visual, int width, int height,
                                            SkiaHelper::RenderMethod renderMethod, bool temporary)
{
    SkiaZone zone;
    sk_app::DisplayParams displayParams;
    displayParams.fColorType = kN32_SkColorType;
    sk_app::window_context_factory::XlibWindowInfo winInfo;
    assert(display);
    winInfo.fDisplay = display;
    winInfo.fWindow = drawable;
    winInfo.fFBConfig = nullptr; // not used
    winInfo.fVisualInfo = const_cast<XVisualInfo*>(visual);
    assert(winInfo.fVisualInfo->visual != nullptr); // make sure it's not an uninitialized SalVisual
    winInfo.fWidth = width;
    winInfo.fHeight = height;
#ifdef DBG_UTIL
    // Our patched Skia has VulkanWindowContext that shares GrContext, which requires
    // that the X11 visual is always the same. Ensure it is so.
    static VisualID checkVisualID = -1U;
    // Exception is for the temporary case during startup, when SkiaHelper's
    // checkDeviceBlacklisted() needs a WindowContext and may be called before SalVisual
    // is ready.
    if (!temporary)
    {
        assert(checkVisualID == -1U || winInfo.fVisualInfo->visualid == checkVisualID);
        checkVisualID = winInfo.fVisualInfo->visualid;
    }
#else
    (void)temporary;
#endif
    switch (renderMethod)
    {
        case SkiaHelper::RenderRaster:
            // TODO The Skia Xlib code actually requires the non-native color type to work properly.
            displayParams.fColorType
                = (displayParams.fColorType == kBGRA_8888_SkColorType ? kRGBA_8888_SkColorType
                                                                      : kBGRA_8888_SkColorType);
            return sk_app::window_context_factory::MakeRasterForXlib(winInfo, displayParams);
        case SkiaHelper::RenderVulkan:
            return sk_app::window_context_factory::MakeVulkanForXlib(winInfo, displayParams);
    }
    abort();
}

bool X11SkiaSalGraphicsImpl::avoidRecreateByResize() const
{
    if (!mSurface || isOffscreen())
        return false;
    // Skia's WindowContext uses actual dimensions of the X window, which due to X11 being
    // asynchronous may be temporarily different from what VCL thinks are the dimensions.
    // That can lead to us repeatedly calling recreateSurface() because of "incorrect"
    // size, and we otherwise need to check for size changes, because VCL does not inform us.
    // Avoid the problem here by checking the size of the X window and bail out if Skia
    // would just return the same size as it is now.
    Window r;
    int x, y;
    unsigned int w, h, border, depth;
    XGetGeometry(mX11Parent.GetXDisplay(), mX11Parent.GetDrawable(), &r, &x, &y, &w, &h, &border,
                 &depth);
    return mSurface->width() == int(w) && mSurface->height() == int(h);
}

void X11SkiaSalGraphicsImpl::DeInit()
{
    SkiaZone zone;
    SkiaSalGraphicsImpl::DeInit();
    mWindowContext.reset();
}

void X11SkiaSalGraphicsImpl::freeResources() {}

void X11SkiaSalGraphicsImpl::performFlush()
{
    SkiaZone zone;
    flushDrawing();
    // TODO XPutImage() is somewhat inefficient, XShmPutImage() should be preferred.
    mWindowContext->swapBuffers();
}

std::unique_ptr<sk_app::WindowContext> createVulkanWindowContext(bool temporary)
{
    SalDisplay* salDisplay = vcl_sal::getSalDisplay(GetGenericUnixSalData());
    const XVisualInfo* visual;
    XVisualInfo* visuals = nullptr;
    if (!temporary)
        visual = &salDisplay->GetVisual(salDisplay->GetDefaultXScreen());
    else
    {
        // SalVisual from salDisplay may not be setup yet at this point, get
        // info for the default visual.
        XVisualInfo search;
        search.visualid = XVisualIDFromVisual(
            DefaultVisual(salDisplay->GetDisplay(), salDisplay->GetDefaultXScreen().getXScreen()));
        int count;
        visuals = XGetVisualInfo(salDisplay->GetDisplay(), VisualIDMask, &search, &count);
        assert(count == 1);
        visual = visuals;
    }
    std::unique_ptr<sk_app::WindowContext> ret = X11SkiaSalGraphicsImpl::createWindowContext(
        salDisplay->GetDisplay(), None, visual, 1, 1, SkiaHelper::RenderVulkan, temporary);
    if (temporary)
        XFree(visuals);
    return ret;
}

void X11SkiaSalGraphicsImpl::prepareSkia() { SkiaHelper::prepareSkia(createVulkanWindowContext); }

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */