135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2012 Red Hat Inc.
3ed6184dfSmrg * Copyright 2019 DisplayLink (UK) Ltd.
435c4bbdfSmrg *
535c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
635c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
735c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
835c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
935c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
1035c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1135c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1235c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1335c4bbdfSmrg * is" without express or implied warranty.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1635c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1735c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1835c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1935c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2035c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2135c4bbdfSmrg * OF THIS SOFTWARE.
2235c4bbdfSmrg *
2335c4bbdfSmrg * Authors: Dave Airlie
2435c4bbdfSmrg */
2535c4bbdfSmrg
2635c4bbdfSmrg#include "randrstr.h"
2735c4bbdfSmrg#include "swaprep.h"
2835c4bbdfSmrg
291b5d61b8Smrg#include <X11/Xatom.h>
301b5d61b8Smrg
31a035e2b2SmrgRESTYPE RRProviderType = 0;
3235c4bbdfSmrg
3335c4bbdfSmrg/*
3435c4bbdfSmrg * Initialize provider type error value
3535c4bbdfSmrg */
3635c4bbdfSmrgvoid
3735c4bbdfSmrgRRProviderInitErrorValue(void)
3835c4bbdfSmrg{
3935c4bbdfSmrg    SetResourceTypeErrorValue(RRProviderType, RRErrorBase + BadRRProvider);
4035c4bbdfSmrg}
4135c4bbdfSmrg
4235c4bbdfSmrg#define ADD_PROVIDER(_pScreen) do {                                 \
4335c4bbdfSmrg    pScrPriv = rrGetScrPriv((_pScreen));                            \
4435c4bbdfSmrg    if (pScrPriv->provider) {                                   \
4535c4bbdfSmrg        providers[count_providers] = pScrPriv->provider->id;    \
4635c4bbdfSmrg        if (client->swapped)                                    \
4735c4bbdfSmrg            swapl(&providers[count_providers]);                 \
4835c4bbdfSmrg        count_providers++;                                      \
4935c4bbdfSmrg    }                                                           \
5035c4bbdfSmrg    } while(0)
5135c4bbdfSmrg
5235c4bbdfSmrgint
5335c4bbdfSmrgProcRRGetProviders (ClientPtr client)
5435c4bbdfSmrg{
5535c4bbdfSmrg    REQUEST(xRRGetProvidersReq);
5635c4bbdfSmrg    xRRGetProvidersReply rep;
5735c4bbdfSmrg    WindowPtr pWin;
5835c4bbdfSmrg    ScreenPtr pScreen;
5935c4bbdfSmrg    rrScrPrivPtr pScrPriv;
6035c4bbdfSmrg    int rc;
6135c4bbdfSmrg    CARD8 *extra;
6235c4bbdfSmrg    unsigned int extraLen;
6335c4bbdfSmrg    RRProvider *providers;
6435c4bbdfSmrg    int total_providers = 0, count_providers = 0;
6535c4bbdfSmrg    ScreenPtr iter;
6635c4bbdfSmrg
6735c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetProvidersReq);
6835c4bbdfSmrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
6935c4bbdfSmrg    if (rc != Success)
7035c4bbdfSmrg        return rc;
7135c4bbdfSmrg
7235c4bbdfSmrg    pScreen = pWin->drawable.pScreen;
7335c4bbdfSmrg
7435c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
7535c4bbdfSmrg
7635c4bbdfSmrg    if (pScrPriv->provider)
7735c4bbdfSmrg        total_providers++;
78ed6184dfSmrg    xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
7935c4bbdfSmrg        pScrPriv = rrGetScrPriv(iter);
8035c4bbdfSmrg        total_providers += pScrPriv->provider ? 1 : 0;
8135c4bbdfSmrg    }
8235c4bbdfSmrg
8335c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
8435c4bbdfSmrg
8535c4bbdfSmrg    if (!pScrPriv)
8635c4bbdfSmrg    {
8735c4bbdfSmrg        rep = (xRRGetProvidersReply) {
8835c4bbdfSmrg            .type = X_Reply,
8935c4bbdfSmrg            .sequenceNumber = client->sequence,
9035c4bbdfSmrg            .length = 0,
9135c4bbdfSmrg            .timestamp = currentTime.milliseconds,
9235c4bbdfSmrg            .nProviders = 0
9335c4bbdfSmrg        };
9435c4bbdfSmrg        extra = NULL;
9535c4bbdfSmrg        extraLen = 0;
9635c4bbdfSmrg    } else {
9735c4bbdfSmrg        rep = (xRRGetProvidersReply) {
9835c4bbdfSmrg            .type = X_Reply,
9935c4bbdfSmrg            .sequenceNumber = client->sequence,
10035c4bbdfSmrg            .timestamp = pScrPriv->lastSetTime.milliseconds,
10135c4bbdfSmrg            .nProviders = total_providers,
10235c4bbdfSmrg            .length = total_providers
10335c4bbdfSmrg        };
10435c4bbdfSmrg        extraLen = rep.length << 2;
10535c4bbdfSmrg        if (extraLen) {
10635c4bbdfSmrg            extra = malloc(extraLen);
10735c4bbdfSmrg            if (!extra)
10835c4bbdfSmrg                return BadAlloc;
10935c4bbdfSmrg        } else
11035c4bbdfSmrg            extra = NULL;
11135c4bbdfSmrg
11235c4bbdfSmrg        providers = (RRProvider *)extra;
11335c4bbdfSmrg        ADD_PROVIDER(pScreen);
114ed6184dfSmrg        xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
11535c4bbdfSmrg            ADD_PROVIDER(iter);
11635c4bbdfSmrg        }
11735c4bbdfSmrg    }
11835c4bbdfSmrg
11935c4bbdfSmrg    if (client->swapped) {
12035c4bbdfSmrg        swaps(&rep.sequenceNumber);
12135c4bbdfSmrg        swapl(&rep.length);
12235c4bbdfSmrg        swapl(&rep.timestamp);
12335c4bbdfSmrg        swaps(&rep.nProviders);
12435c4bbdfSmrg    }
12535c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetProvidersReply), (char *)&rep);
12635c4bbdfSmrg    if (extraLen)
12735c4bbdfSmrg    {
12835c4bbdfSmrg        WriteToClient (client, extraLen, (char *) extra);
12935c4bbdfSmrg        free(extra);
13035c4bbdfSmrg    }
13135c4bbdfSmrg    return Success;
13235c4bbdfSmrg}
13335c4bbdfSmrg
13435c4bbdfSmrgint
13535c4bbdfSmrgProcRRGetProviderInfo (ClientPtr client)
13635c4bbdfSmrg{
13735c4bbdfSmrg    REQUEST(xRRGetProviderInfoReq);
13835c4bbdfSmrg    xRRGetProviderInfoReply rep;
13935c4bbdfSmrg    rrScrPrivPtr pScrPriv, pScrProvPriv;
14035c4bbdfSmrg    RRProviderPtr provider;
14135c4bbdfSmrg    ScreenPtr pScreen;
14235c4bbdfSmrg    CARD8 *extra;
14335c4bbdfSmrg    unsigned int extraLen = 0;
14435c4bbdfSmrg    RRCrtc *crtcs;
14535c4bbdfSmrg    RROutput *outputs;
14635c4bbdfSmrg    int i;
14735c4bbdfSmrg    char *name;
14835c4bbdfSmrg    ScreenPtr provscreen;
14935c4bbdfSmrg    RRProvider *providers;
15035c4bbdfSmrg    uint32_t *prov_cap;
15135c4bbdfSmrg
15235c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetProviderInfoReq);
15335c4bbdfSmrg    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
15435c4bbdfSmrg
15535c4bbdfSmrg    pScreen = provider->pScreen;
15635c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
15735c4bbdfSmrg
15835c4bbdfSmrg    rep = (xRRGetProviderInfoReply) {
15935c4bbdfSmrg        .type = X_Reply,
16035c4bbdfSmrg        .status = RRSetConfigSuccess,
16135c4bbdfSmrg        .sequenceNumber = client->sequence,
16235c4bbdfSmrg        .length = 0,
16335c4bbdfSmrg        .capabilities = provider->capabilities,
16435c4bbdfSmrg        .nameLength = provider->nameLength,
16535c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
16635c4bbdfSmrg        .nCrtcs = pScrPriv->numCrtcs,
16735c4bbdfSmrg        .nOutputs = pScrPriv->numOutputs,
16835c4bbdfSmrg        .nAssociatedProviders = 0
16935c4bbdfSmrg    };
17035c4bbdfSmrg
17135c4bbdfSmrg    /* count associated providers */
17235c4bbdfSmrg    if (provider->offload_sink)
17335c4bbdfSmrg        rep.nAssociatedProviders++;
1741b5d61b8Smrg    if (provider->output_source &&
1751b5d61b8Smrg            provider->output_source != provider->offload_sink)
17635c4bbdfSmrg        rep.nAssociatedProviders++;
177ed6184dfSmrg    xorg_list_for_each_entry(provscreen, &pScreen->secondary_list, secondary_head) {
178ed6184dfSmrg        if (provscreen->is_output_secondary || provscreen->is_offload_secondary)
1791b5d61b8Smrg            rep.nAssociatedProviders++;
1801b5d61b8Smrg    }
18135c4bbdfSmrg
18235c4bbdfSmrg    rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs +
18335c4bbdfSmrg                  (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength));
18435c4bbdfSmrg
18535c4bbdfSmrg    extraLen = rep.length << 2;
18635c4bbdfSmrg    if (extraLen) {
18735c4bbdfSmrg        extra = malloc(extraLen);
18835c4bbdfSmrg        if (!extra)
18935c4bbdfSmrg            return BadAlloc;
19035c4bbdfSmrg    }
19135c4bbdfSmrg    else
19235c4bbdfSmrg        extra = NULL;
19335c4bbdfSmrg
19435c4bbdfSmrg    crtcs = (RRCrtc *)extra;
19535c4bbdfSmrg    outputs = (RROutput *)(crtcs + rep.nCrtcs);
19635c4bbdfSmrg    providers = (RRProvider *)(outputs + rep.nOutputs);
19735c4bbdfSmrg    prov_cap = (unsigned int *)(providers + rep.nAssociatedProviders);
19835c4bbdfSmrg    name = (char *)(prov_cap + rep.nAssociatedProviders);
19935c4bbdfSmrg
20035c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
20135c4bbdfSmrg        crtcs[i] = pScrPriv->crtcs[i]->id;
20235c4bbdfSmrg        if (client->swapped)
20335c4bbdfSmrg            swapl(&crtcs[i]);
20435c4bbdfSmrg    }
20535c4bbdfSmrg
20635c4bbdfSmrg    for (i = 0; i < pScrPriv->numOutputs; i++) {
20735c4bbdfSmrg        outputs[i] = pScrPriv->outputs[i]->id;
20835c4bbdfSmrg        if (client->swapped)
20935c4bbdfSmrg            swapl(&outputs[i]);
21035c4bbdfSmrg    }
21135c4bbdfSmrg
21235c4bbdfSmrg    i = 0;
21335c4bbdfSmrg    if (provider->offload_sink) {
21435c4bbdfSmrg        providers[i] = provider->offload_sink->id;
21535c4bbdfSmrg        if (client->swapped)
21635c4bbdfSmrg            swapl(&providers[i]);
21735c4bbdfSmrg        prov_cap[i] = RR_Capability_SinkOffload;
21835c4bbdfSmrg        if (client->swapped)
21935c4bbdfSmrg            swapl(&prov_cap[i]);
22035c4bbdfSmrg        i++;
22135c4bbdfSmrg    }
22235c4bbdfSmrg    if (provider->output_source) {
22335c4bbdfSmrg        providers[i] = provider->output_source->id;
22435c4bbdfSmrg        if (client->swapped)
22535c4bbdfSmrg            swapl(&providers[i]);
22635c4bbdfSmrg        prov_cap[i] = RR_Capability_SourceOutput;
22735c4bbdfSmrg            swapl(&prov_cap[i]);
22835c4bbdfSmrg        i++;
22935c4bbdfSmrg    }
230ed6184dfSmrg    xorg_list_for_each_entry(provscreen, &pScreen->secondary_list, secondary_head) {
231ed6184dfSmrg        if (!provscreen->is_output_secondary && !provscreen->is_offload_secondary)
2321b5d61b8Smrg            continue;
23335c4bbdfSmrg        pScrProvPriv = rrGetScrPriv(provscreen);
23435c4bbdfSmrg        providers[i] = pScrProvPriv->provider->id;
23535c4bbdfSmrg        if (client->swapped)
23635c4bbdfSmrg            swapl(&providers[i]);
2371b5d61b8Smrg        prov_cap[i] = 0;
238ed6184dfSmrg        if (provscreen->is_output_secondary)
2391b5d61b8Smrg            prov_cap[i] |= RR_Capability_SinkOutput;
240ed6184dfSmrg        if (provscreen->is_offload_secondary)
2411b5d61b8Smrg            prov_cap[i] |= RR_Capability_SourceOffload;
24235c4bbdfSmrg        if (client->swapped)
24335c4bbdfSmrg            swapl(&prov_cap[i]);
24435c4bbdfSmrg        i++;
24535c4bbdfSmrg    }
24635c4bbdfSmrg
24735c4bbdfSmrg    memcpy(name, provider->name, rep.nameLength);
24835c4bbdfSmrg    if (client->swapped) {
24935c4bbdfSmrg              swaps(&rep.sequenceNumber);
25035c4bbdfSmrg        swapl(&rep.length);
25135c4bbdfSmrg        swapl(&rep.capabilities);
25235c4bbdfSmrg        swaps(&rep.nCrtcs);
25335c4bbdfSmrg        swaps(&rep.nOutputs);
25435c4bbdfSmrg        swaps(&rep.nameLength);
25535c4bbdfSmrg    }
25635c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetProviderInfoReply), (char *)&rep);
25735c4bbdfSmrg    if (extraLen)
25835c4bbdfSmrg    {
25935c4bbdfSmrg        WriteToClient (client, extraLen, (char *) extra);
26035c4bbdfSmrg        free(extra);
26135c4bbdfSmrg    }
26235c4bbdfSmrg    return Success;
26335c4bbdfSmrg}
26435c4bbdfSmrg
2651b5d61b8Smrgstatic void
2661b5d61b8SmrgRRInitPrimeSyncProps(ScreenPtr pScreen)
2671b5d61b8Smrg{
2681b5d61b8Smrg    /*
2691b5d61b8Smrg     * TODO: When adding support for different sources for different outputs,
2701b5d61b8Smrg     * make sure this sets up the output properties only on outputs associated
2711b5d61b8Smrg     * with the correct source provider.
2721b5d61b8Smrg     */
2731b5d61b8Smrg
2741b5d61b8Smrg    rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
2751b5d61b8Smrg
2761b5d61b8Smrg    const char *syncStr = PRIME_SYNC_PROP;
2771b5d61b8Smrg    Atom syncProp = MakeAtom(syncStr, strlen(syncStr), TRUE);
2781b5d61b8Smrg
2791b5d61b8Smrg    int defaultVal = TRUE;
2801b5d61b8Smrg    INT32 validVals[2] = {FALSE, TRUE};
2811b5d61b8Smrg
2821b5d61b8Smrg    int i;
2831b5d61b8Smrg    for (i = 0; i < pScrPriv->numOutputs; i++) {
2841b5d61b8Smrg        if (!RRQueryOutputProperty(pScrPriv->outputs[i], syncProp)) {
2851b5d61b8Smrg            RRConfigureOutputProperty(pScrPriv->outputs[i], syncProp,
2861b5d61b8Smrg                                      TRUE, FALSE, FALSE,
2871b5d61b8Smrg                                      2, &validVals[0]);
2881b5d61b8Smrg            RRChangeOutputProperty(pScrPriv->outputs[i], syncProp, XA_INTEGER,
2891b5d61b8Smrg                                   8, PropModeReplace, 1, &defaultVal,
2901b5d61b8Smrg                                   FALSE, FALSE);
2911b5d61b8Smrg        }
2921b5d61b8Smrg    }
2931b5d61b8Smrg}
2941b5d61b8Smrg
2951b5d61b8Smrgstatic void
2961b5d61b8SmrgRRFiniPrimeSyncProps(ScreenPtr pScreen)
2971b5d61b8Smrg{
2981b5d61b8Smrg    /*
2991b5d61b8Smrg     * TODO: When adding support for different sources for different outputs,
3001b5d61b8Smrg     * make sure this tears down the output properties only on outputs
3011b5d61b8Smrg     * associated with the correct source provider.
3021b5d61b8Smrg     */
3031b5d61b8Smrg
3041b5d61b8Smrg    rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
3051b5d61b8Smrg    int i;
3061b5d61b8Smrg
3071b5d61b8Smrg    const char *syncStr = PRIME_SYNC_PROP;
3081b5d61b8Smrg    Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
3091b5d61b8Smrg    if (syncProp == None)
3101b5d61b8Smrg        return;
3111b5d61b8Smrg
3121b5d61b8Smrg    for (i = 0; i < pScrPriv->numOutputs; i++) {
3131b5d61b8Smrg        RRDeleteOutputProperty(pScrPriv->outputs[i], syncProp);
3141b5d61b8Smrg    }
3151b5d61b8Smrg}
3161b5d61b8Smrg
31735c4bbdfSmrgint
31835c4bbdfSmrgProcRRSetProviderOutputSource(ClientPtr client)
31935c4bbdfSmrg{
32035c4bbdfSmrg    REQUEST(xRRSetProviderOutputSourceReq);
32135c4bbdfSmrg    rrScrPrivPtr pScrPriv;
32235c4bbdfSmrg    RRProviderPtr provider, source_provider = NULL;
32335c4bbdfSmrg    ScreenPtr pScreen;
32435c4bbdfSmrg
32535c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRSetProviderOutputSourceReq);
32635c4bbdfSmrg
32735c4bbdfSmrg    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
32835c4bbdfSmrg
32935c4bbdfSmrg    if (!(provider->capabilities & RR_Capability_SinkOutput))
33035c4bbdfSmrg        return BadValue;
33135c4bbdfSmrg
33235c4bbdfSmrg    if (stuff->source_provider) {
33335c4bbdfSmrg        VERIFY_RR_PROVIDER(stuff->source_provider, source_provider, DixReadAccess);
33435c4bbdfSmrg
33535c4bbdfSmrg        if (!(source_provider->capabilities & RR_Capability_SourceOutput))
33635c4bbdfSmrg            return BadValue;
33735c4bbdfSmrg    }
33835c4bbdfSmrg
33935c4bbdfSmrg    pScreen = provider->pScreen;
34035c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
34135c4bbdfSmrg
3421b5d61b8Smrg    if (!pScreen->isGPU)
3431b5d61b8Smrg        return BadValue;
3441b5d61b8Smrg
34535c4bbdfSmrg    pScrPriv->rrProviderSetOutputSource(pScreen, provider, source_provider);
34635c4bbdfSmrg
3471b5d61b8Smrg    RRInitPrimeSyncProps(pScreen);
3481b5d61b8Smrg
34935c4bbdfSmrg    provider->changed = TRUE;
35035c4bbdfSmrg    RRSetChanged(pScreen);
35135c4bbdfSmrg
35235c4bbdfSmrg    RRTellChanged (pScreen);
35335c4bbdfSmrg
35435c4bbdfSmrg    return Success;
35535c4bbdfSmrg}
35635c4bbdfSmrg
35735c4bbdfSmrgint
35835c4bbdfSmrgProcRRSetProviderOffloadSink(ClientPtr client)
35935c4bbdfSmrg{
36035c4bbdfSmrg    REQUEST(xRRSetProviderOffloadSinkReq);
36135c4bbdfSmrg    rrScrPrivPtr pScrPriv;
36235c4bbdfSmrg    RRProviderPtr provider, sink_provider = NULL;
36335c4bbdfSmrg    ScreenPtr pScreen;
36435c4bbdfSmrg
36535c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRSetProviderOffloadSinkReq);
36635c4bbdfSmrg
36735c4bbdfSmrg    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
36835c4bbdfSmrg    if (!(provider->capabilities & RR_Capability_SourceOffload))
36935c4bbdfSmrg        return BadValue;
37035c4bbdfSmrg    if (!provider->pScreen->isGPU)
37135c4bbdfSmrg        return BadValue;
37235c4bbdfSmrg
37335c4bbdfSmrg    if (stuff->sink_provider) {
37435c4bbdfSmrg        VERIFY_RR_PROVIDER(stuff->sink_provider, sink_provider, DixReadAccess);
37535c4bbdfSmrg        if (!(sink_provider->capabilities & RR_Capability_SinkOffload))
37635c4bbdfSmrg            return BadValue;
37735c4bbdfSmrg    }
37835c4bbdfSmrg    pScreen = provider->pScreen;
37935c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
38035c4bbdfSmrg
38135c4bbdfSmrg    pScrPriv->rrProviderSetOffloadSink(pScreen, provider, sink_provider);
38235c4bbdfSmrg
38335c4bbdfSmrg    provider->changed = TRUE;
38435c4bbdfSmrg    RRSetChanged(pScreen);
38535c4bbdfSmrg
38635c4bbdfSmrg    RRTellChanged (pScreen);
38735c4bbdfSmrg
38835c4bbdfSmrg    return Success;
38935c4bbdfSmrg}
39035c4bbdfSmrg
39135c4bbdfSmrgRRProviderPtr
39235c4bbdfSmrgRRProviderCreate(ScreenPtr pScreen, const char *name,
39335c4bbdfSmrg                 int nameLength)
39435c4bbdfSmrg{
39535c4bbdfSmrg    RRProviderPtr provider;
39635c4bbdfSmrg    rrScrPrivPtr pScrPriv;
39735c4bbdfSmrg
39835c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
39935c4bbdfSmrg
40035c4bbdfSmrg    provider = calloc(1, sizeof(RRProviderRec) + nameLength + 1);
40135c4bbdfSmrg    if (!provider)
40235c4bbdfSmrg        return NULL;
40335c4bbdfSmrg
40435c4bbdfSmrg    provider->id = FakeClientID(0);
40535c4bbdfSmrg    provider->pScreen = pScreen;
40635c4bbdfSmrg    provider->name = (char *) (provider + 1);
40735c4bbdfSmrg    provider->nameLength = nameLength;
40835c4bbdfSmrg    memcpy(provider->name, name, nameLength);
40935c4bbdfSmrg    provider->name[nameLength] = '\0';
41035c4bbdfSmrg    provider->changed = FALSE;
41135c4bbdfSmrg
41235c4bbdfSmrg    if (!AddResource (provider->id, RRProviderType, (void *) provider))
41335c4bbdfSmrg        return NULL;
41435c4bbdfSmrg    pScrPriv->provider = provider;
41535c4bbdfSmrg    return provider;
41635c4bbdfSmrg}
41735c4bbdfSmrg
41835c4bbdfSmrg/*
41935c4bbdfSmrg * Destroy a provider at shutdown
42035c4bbdfSmrg */
42135c4bbdfSmrgvoid
42235c4bbdfSmrgRRProviderDestroy (RRProviderPtr provider)
42335c4bbdfSmrg{
4241b5d61b8Smrg    RRFiniPrimeSyncProps(provider->pScreen);
42535c4bbdfSmrg    FreeResource (provider->id, 0);
42635c4bbdfSmrg}
42735c4bbdfSmrg
42835c4bbdfSmrgvoid
42935c4bbdfSmrgRRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities)
43035c4bbdfSmrg{
43135c4bbdfSmrg    provider->capabilities = capabilities;
43235c4bbdfSmrg}
43335c4bbdfSmrg
43435c4bbdfSmrgstatic int
43535c4bbdfSmrgRRProviderDestroyResource (void *value, XID pid)
43635c4bbdfSmrg{
43735c4bbdfSmrg    RRProviderPtr provider = (RRProviderPtr)value;
43835c4bbdfSmrg    ScreenPtr pScreen = provider->pScreen;
43935c4bbdfSmrg
44035c4bbdfSmrg    if (pScreen)
44135c4bbdfSmrg    {
44235c4bbdfSmrg        rrScrPriv(pScreen);
44335c4bbdfSmrg
44435c4bbdfSmrg        if (pScrPriv->rrProviderDestroy)
44535c4bbdfSmrg            (*pScrPriv->rrProviderDestroy)(pScreen, provider);
44635c4bbdfSmrg        pScrPriv->provider = NULL;
44735c4bbdfSmrg    }
44835c4bbdfSmrg    free(provider);
44935c4bbdfSmrg    return 1;
45035c4bbdfSmrg}
45135c4bbdfSmrg
45235c4bbdfSmrgBool
45335c4bbdfSmrgRRProviderInit(void)
45435c4bbdfSmrg{
45535c4bbdfSmrg    RRProviderType = CreateNewResourceType(RRProviderDestroyResource, "Provider");
45635c4bbdfSmrg    if (!RRProviderType)
45735c4bbdfSmrg        return FALSE;
45835c4bbdfSmrg
45935c4bbdfSmrg    return TRUE;
46035c4bbdfSmrg}
46135c4bbdfSmrg
46235c4bbdfSmrgextern _X_EXPORT Bool
46335c4bbdfSmrgRRProviderLookup(XID id, RRProviderPtr *provider_p)
46435c4bbdfSmrg{
46535c4bbdfSmrg    int rc = dixLookupResourceByType((void **)provider_p, id,
46635c4bbdfSmrg                                   RRProviderType, NullClient, DixReadAccess);
46735c4bbdfSmrg    if (rc == Success)
46835c4bbdfSmrg        return TRUE;
46935c4bbdfSmrg    return FALSE;
47035c4bbdfSmrg}
47135c4bbdfSmrg
47235c4bbdfSmrgvoid
47335c4bbdfSmrgRRDeliverProviderEvent(ClientPtr client, WindowPtr pWin, RRProviderPtr provider)
47435c4bbdfSmrg{
47535c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
47635c4bbdfSmrg
47735c4bbdfSmrg    rrScrPriv(pScreen);
47835c4bbdfSmrg
47935c4bbdfSmrg    xRRProviderChangeNotifyEvent pe = {
48035c4bbdfSmrg        .type = RRNotify + RREventBase,
48135c4bbdfSmrg        .subCode = RRNotify_ProviderChange,
48235c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
48335c4bbdfSmrg        .window = pWin->drawable.id,
48435c4bbdfSmrg        .provider = provider->id
48535c4bbdfSmrg    };
48635c4bbdfSmrg
48735c4bbdfSmrg    WriteEventsToClient(client, 1, (xEvent *) &pe);
48835c4bbdfSmrg}
489ed6184dfSmrg
490ed6184dfSmrgvoid
491ed6184dfSmrgRRProviderAutoConfigGpuScreen(ScreenPtr pScreen, ScreenPtr primaryScreen)
492ed6184dfSmrg{
493ed6184dfSmrg    rrScrPrivPtr pScrPriv;
494ed6184dfSmrg    rrScrPrivPtr primaryPriv;
495ed6184dfSmrg    RRProviderPtr provider;
496ed6184dfSmrg    RRProviderPtr primary_provider;
497ed6184dfSmrg
498ed6184dfSmrg    /* Bail out if RandR wasn't initialized. */
499ed6184dfSmrg    if (!dixPrivateKeyRegistered(rrPrivKey))
500ed6184dfSmrg        return;
501ed6184dfSmrg
502ed6184dfSmrg    pScrPriv = rrGetScrPriv(pScreen);
503ed6184dfSmrg    primaryPriv = rrGetScrPriv(primaryScreen);
504ed6184dfSmrg
505ed6184dfSmrg    provider = pScrPriv->provider;
506ed6184dfSmrg    primary_provider = primaryPriv->provider;
507ed6184dfSmrg
508ed6184dfSmrg    if (!provider || !primary_provider)
509ed6184dfSmrg        return;
510ed6184dfSmrg
511ed6184dfSmrg    if ((provider->capabilities & RR_Capability_SinkOutput) &&
512ed6184dfSmrg        (primary_provider->capabilities & RR_Capability_SourceOutput)) {
513ed6184dfSmrg        pScrPriv->rrProviderSetOutputSource(pScreen, provider, primary_provider);
514ed6184dfSmrg        RRInitPrimeSyncProps(pScreen);
515ed6184dfSmrg
516ed6184dfSmrg        primaryPriv->configChanged = TRUE;
517ed6184dfSmrg        RRSetChanged(primaryScreen);
518ed6184dfSmrg    }
519ed6184dfSmrg
520ed6184dfSmrg    if ((provider->capabilities & RR_Capability_SourceOffload) &&
521ed6184dfSmrg        (primary_provider->capabilities & RR_Capability_SinkOffload))
522ed6184dfSmrg        pScrPriv->rrProviderSetOffloadSink(pScreen, provider, primary_provider);
523ed6184dfSmrg}
524