/* * Copyright © 2012 Red Hat Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * that the name of the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. * * Authors: Dave Airlie */ #include "randrstr.h" #include "swaprep.h" RESTYPE RRProviderType; /* * Initialize provider type error value */ void RRProviderInitErrorValue(void) { #ifndef NXAGENT_SERVER SetResourceTypeErrorValue(RRProviderType, RRErrorBase + BadRRProvider); #endif } #define ADD_PROVIDER(_pScreen) do { \ pScrPriv = rrGetScrPriv((_pScreen)); \ if (pScrPriv->provider) { \ providers[count_providers] = pScrPriv->provider->id; \ if (client->swapped) \ swapl(&providers[count_providers]); \ count_providers++; \ } \ } while(0) int ProcRRGetProviders(ClientPtr client) { REQUEST(xRRGetProvidersReq); xRRGetProvidersReply rep; WindowPtr pWin; ScreenPtr pScreen; rrScrPrivPtr pScrPriv; int rc; CARD8 *extra; unsigned int extraLen; RRProvider *providers; int total_providers = 0, count_providers = 0; #ifndef NXAGENT_SERVER ScreenPtr iter; #endif REQUEST_SIZE_MATCH(xRRGetProvidersReq); #ifndef NXAGENT_SERVER rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); #else pWin = SecurityLookupWindow(stuff->window, client, DixReadAccess); rc = pWin ? Success : BadWindow; #endif if (rc != Success) return rc; pScreen = pWin->drawable.pScreen; pScrPriv = rrGetScrPriv(pScreen); if (pScrPriv->provider) total_providers++; #ifndef NXAGENT_SERVER xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { pScrPriv = rrGetScrPriv(iter); total_providers += pScrPriv->provider ? 1 : 0; } xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { pScrPriv = rrGetScrPriv(iter); total_providers += pScrPriv->provider ? 1 : 0; } xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { pScrPriv = rrGetScrPriv(iter); total_providers += pScrPriv->provider ? 1 : 0; } #endif pScrPriv = rrGetScrPriv(pScreen); if (!pScrPriv) { rep = (xRRGetProvidersReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = 0, .timestamp = currentTime.milliseconds, .nProviders = 0 }; extra = NULL; extraLen = 0; } else { rep = (xRRGetProvidersReply) { .type = X_Reply, .sequenceNumber = client->sequence, .timestamp = pScrPriv->lastSetTime.milliseconds, .nProviders = total_providers, .length = total_providers }; extraLen = rep.length << 2; if (extraLen) { extra = calloc(1, extraLen); if (!extra) return BadAlloc; } else extra = NULL; providers = (RRProvider *) extra; ADD_PROVIDER(pScreen); #ifndef NXAGENT_SERVER xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { ADD_PROVIDER(iter); } xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { ADD_PROVIDER(iter); } xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { ADD_PROVIDER(iter); } #endif } if (client->swapped) { swaps(&rep.sequenceNumber); swapl(&rep.length); swapl(&rep.timestamp); swaps(&rep.nProviders); } WriteToClient(client, sizeof(xRRGetProvidersReply), &rep); if (extraLen) { WriteToClient(client, extraLen, extra); free(extra); } return Success; } int ProcRRGetProviderInfo(ClientPtr client) { REQUEST(xRRGetProviderInfoReq); xRRGetProviderInfoReply rep; rrScrPrivPtr pScrPriv; #ifndef NXAGENT_SERVER rrScrPrivPtr pScrProvPriv; #endif RRProviderPtr provider; ScreenPtr pScreen; CARD8 *extra; unsigned int extraLen = 0; RRCrtc *crtcs; RROutput *outputs; int i; char *name; #ifndef NXAGENT_SERVER ScreenPtr provscreen; #endif RRProvider *providers; uint32_t *prov_cap; REQUEST_SIZE_MATCH(xRRGetProviderInfoReq); VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); pScreen = provider->pScreen; pScrPriv = rrGetScrPriv(pScreen); rep = (xRRGetProviderInfoReply) { .type = X_Reply, .status = RRSetConfigSuccess, .sequenceNumber = client->sequence, .length = 0, .capabilities = provider->capabilities, .nameLength = provider->nameLength, .timestamp = pScrPriv->lastSetTime.milliseconds, .nCrtcs = pScrPriv->numCrtcs, .nOutputs = pScrPriv->numOutputs, .nAssociatedProviders = 0 }; /* count associated providers */ if (provider->offload_sink) rep.nAssociatedProviders++; if (provider->output_source) rep.nAssociatedProviders++; #ifndef NXAGENT_SERVER xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) rep.nAssociatedProviders++; xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) rep.nAssociatedProviders++; #endif rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs + (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength)); extraLen = rep.length << 2; if (extraLen) { extra = calloc(1, extraLen); if (!extra) return BadAlloc; } else extra = NULL; crtcs = (RRCrtc *) extra; outputs = (RROutput *) (crtcs + rep.nCrtcs); providers = (RRProvider *) (outputs + rep.nOutputs); prov_cap = (unsigned int *) (providers + rep.nAssociatedProviders); name = (char *) (prov_cap + rep.nAssociatedProviders); for (i = 0; i < pScrPriv->numCrtcs; i++) { crtcs[i] = pScrPriv->crtcs[i]->id; if (client->swapped) swapl(&crtcs[i]); } for (i = 0; i < pScrPriv->numOutputs; i++) { outputs[i] = pScrPriv->outputs[i]->id; if (client->swapped) swapl(&outputs[i]); } i = 0; if (provider->offload_sink) { providers[i] = provider->offload_sink->id; if (client->swapped) swapl(&providers[i]); prov_cap[i] = RR_Capability_SinkOffload; if (client->swapped) swapl(&prov_cap[i]); i++; } if (provider->output_source) { providers[i] = provider->output_source->id; if (client->swapped) swapl(&providers[i]); prov_cap[i] = RR_Capability_SourceOutput; swapl(&prov_cap[i]); i++; } #ifndef NXAGENT_SERVER xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) { pScrProvPriv = rrGetScrPriv(provscreen); providers[i] = pScrProvPriv->provider->id; if (client->swapped) swapl(&providers[i]); prov_cap[i] = RR_Capability_SinkOutput; if (client->swapped) swapl(&prov_cap[i]); i++; } xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) { pScrProvPriv = rrGetScrPriv(provscreen); providers[i] = pScrProvPriv->provider->id; if (client->swapped) swapl(&providers[i]); prov_cap[i] = RR_Capability_SourceOffload; if (client->swapped) swapl(&prov_cap[i]); i++; } #endif memcpy(name, provider->name, rep.nameLength); if (client->swapped) { swaps(&rep.sequenceNumber); swapl(&rep.length); swapl(&rep.capabilities); swaps(&rep.nCrtcs); swaps(&rep.nOutputs); swaps(&rep.nameLength); } WriteToClient(client, sizeof(xRRGetProviderInfoReply), &rep); if (extraLen) { WriteToClient(client, extraLen, extra); free(extra); } return Success; } int ProcRRSetProviderOutputSource(ClientPtr client) { REQUEST(xRRSetProviderOutputSourceReq); rrScrPrivPtr pScrPriv; RRProviderPtr provider, source_provider = NULL; ScreenPtr pScreen; REQUEST_SIZE_MATCH(xRRSetProviderOutputSourceReq); VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); if (!(provider->capabilities & RR_Capability_SinkOutput)) return BadValue; if (stuff->source_provider) { VERIFY_RR_PROVIDER(stuff->source_provider, source_provider, DixReadAccess); if (!(source_provider->capabilities & RR_Capability_SourceOutput)) return BadValue; } pScreen = provider->pScreen; pScrPriv = rrGetScrPriv(pScreen); pScrPriv->rrProviderSetOutputSource(pScreen, provider, source_provider); provider->changed = TRUE; RRSetChanged(pScreen); RRTellChanged(pScreen); return Success; } int ProcRRSetProviderOffloadSink(ClientPtr client) { REQUEST(xRRSetProviderOffloadSinkReq); rrScrPrivPtr pScrPriv; RRProviderPtr provider, sink_provider = NULL; ScreenPtr pScreen; REQUEST_SIZE_MATCH(xRRSetProviderOffloadSinkReq); VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); if (!(provider->capabilities & RR_Capability_SourceOffload)) return BadValue; #ifndef NXAGENT_SERVER if (!provider->pScreen->isGPU) return BadValue; #endif /* !defined(NXAGENT_SERVER) */ if (stuff->sink_provider) { VERIFY_RR_PROVIDER(stuff->sink_provider, sink_provider, DixReadAccess); if (!(sink_provider->capabilities & RR_Capability_SinkOffload)) return BadValue; } pScreen = provider->pScreen; pScrPriv = rrGetScrPriv(pScreen); pScrPriv->rrProviderSetOffloadSink(pScreen, provider, sink_provider); provider->changed = TRUE; RRSetChanged(pScreen); RRTellChanged(pScreen); return Success; } RRProviderPtr RRProviderCreate(ScreenPtr pScreen, const char *name, int nameLength) { RRProviderPtr provider; rrScrPrivPtr pScrPriv; pScrPriv = rrGetScrPriv(pScreen); provider = calloc(1, sizeof(RRProviderRec) + nameLength + 1); if (!provider) return NULL; provider->id = FakeClientID(0); provider->pScreen = pScreen; provider->name = (char *) (provider + 1); provider->nameLength = nameLength; memcpy(provider->name, name, nameLength); provider->name[nameLength] = '\0'; provider->changed = FALSE; if (!AddResource(provider->id, RRProviderType, (void *) provider)) return NULL; pScrPriv->provider = provider; return provider; } /* * Destroy a provider at shutdown */ void RRProviderDestroy(RRProviderPtr provider) { FreeResource(provider->id, 0); } void RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities) { provider->capabilities = capabilities; } static int RRProviderDestroyResource(void *value, XID pid) { RRProviderPtr provider = (RRProviderPtr) value; ScreenPtr pScreen = provider->pScreen; if (pScreen) { rrScrPriv(pScreen); if (pScrPriv->rrProviderDestroy) (*pScrPriv->rrProviderDestroy) (pScreen, provider); pScrPriv->provider = NULL; } free(provider); return 1; } Bool RRProviderInit(void) { RRProviderType = CreateNewResourceType(RRProviderDestroyResource #ifndef NXAGENT_SERVER , "Provider" #endif /* !defined(NXAGENT_SERVER) */ ); if (!RRProviderType) return FALSE; #ifdef NXAGENT_SERVER RegisterResourceName(RRProviderType, "Provider"); #endif return TRUE; } extern _X_EXPORT Bool RRProviderLookup(XID id, RRProviderPtr * provider_p) { #ifndef NXAGENT_SERVER int rc = dixLookupResourceByType((void **) provider_p, id, RRProviderType, NullClient, DixReadAccess); if (rc == Success) return TRUE; #else /* !defined(NXAGENT_SERVER) */ provider_p = (RRProviderPtr *) LookupIDByType(id, RREventType); if (provider_p) return TRUE; #endif /* !defined(NXAGENT_SERVER) */ return FALSE; } void RRDeliverProviderEvent(ClientPtr client, WindowPtr pWin, RRProviderPtr provider) { ScreenPtr pScreen = pWin->drawable.pScreen; rrScrPriv(pScreen); xRRProviderChangeNotifyEvent pe = { .type = RRNotify + RREventBase, .subCode = RRNotify_ProviderChange, #ifdef NXAGENT_SERVER .sequenceNumber = client->sequence, #endif .timestamp = pScrPriv->lastSetTime.milliseconds, .window = pWin->drawable.id, .provider = provider->id }; WriteEventsToClient(client, 1, (xEvent *) &pe); }