1d6c0b56eSmrg/* 2d6c0b56eSmrg * Copyright © 2009 Red Hat, Inc. 3d6c0b56eSmrg * 4d6c0b56eSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5d6c0b56eSmrg * copy of this software and associated documentation files (the "Software"), 6d6c0b56eSmrg * to deal in the Software without restriction, including without limitation 7d6c0b56eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d6c0b56eSmrg * and/or sell copies of the Software, and to permit persons to whom the 9d6c0b56eSmrg * Software is furnished to do so, subject to the following conditions: 10d6c0b56eSmrg * 11d6c0b56eSmrg * The above copyright notice and this permission notice (including the next 12d6c0b56eSmrg * paragraph) shall be included in all copies or substantial portions of the 13d6c0b56eSmrg * Software. 14d6c0b56eSmrg * 15d6c0b56eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d6c0b56eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d6c0b56eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d6c0b56eSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d6c0b56eSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20d6c0b56eSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21d6c0b56eSmrg * SOFTWARE. 22d6c0b56eSmrg * 23d6c0b56eSmrg * Authors: 24d6c0b56eSmrg * Dave Airlie <airlied@redhat.com> 25d6c0b56eSmrg * 26d6c0b56eSmrg */ 27d6c0b56eSmrg#ifdef HAVE_CONFIG_H 28d6c0b56eSmrg#include "config.h" 29d6c0b56eSmrg#endif 30d6c0b56eSmrg 31d6c0b56eSmrg#include <errno.h> 32d6c0b56eSmrg#include <sys/ioctl.h> 33d6c0b56eSmrg/* Driver data structures */ 34d6c0b56eSmrg#include "amdgpu_drv.h" 3524b90cf4Smrg#include "amdgpu_bo_helper.h" 36d6c0b56eSmrg#include "amdgpu_drm_queue.h" 37d6c0b56eSmrg#include "amdgpu_glamor.h" 38d6c0b56eSmrg#include "amdgpu_probe.h" 39d6c0b56eSmrg#include "micmap.h" 4024b90cf4Smrg#include "mipointrst.h" 41d6c0b56eSmrg 42d6c0b56eSmrg#include "amdgpu_version.h" 43d6c0b56eSmrg#include "shadow.h" 44504d986fSmrg#include <xf86Priv.h> 45d6c0b56eSmrg 4624b90cf4Smrg#if HAVE_PRESENT_H 4724b90cf4Smrg#include <present.h> 4824b90cf4Smrg#endif 4924b90cf4Smrg 50d6c0b56eSmrg/* DPMS */ 51d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71 52d6c0b56eSmrg#include <X11/extensions/dpmsconst.h> 53d6c0b56eSmrg#else 54d6c0b56eSmrg#define DPMS_SERVER 55d6c0b56eSmrg#include <X11/extensions/dpms.h> 56d6c0b56eSmrg#endif 57d6c0b56eSmrg 58504d986fSmrg#include <X11/extensions/damageproto.h> 59504d986fSmrg 60d6c0b56eSmrg#include "amdgpu_bo_helper.h" 61d6c0b56eSmrg#include "amdgpu_pixmap.h" 62d6c0b56eSmrg 63d6c0b56eSmrg#include <gbm.h> 64d6c0b56eSmrg 6590f2b693Smrgstatic DevPrivateKeyRec amdgpu_window_private_key; 66504d986fSmrgstatic DevScreenPrivateKeyRec amdgpu_client_private_key; 6724b90cf4SmrgDevScreenPrivateKeyRec amdgpu_device_private_key; 68504d986fSmrg 6990f2b693Smrgstatic Atom amdgpu_vrr_atom; 7090f2b693Smrgstatic Bool amdgpu_property_vectors_wrapped; 7190f2b693Smrgstatic Bool restore_property_vector; 7290f2b693Smrgstatic int (*saved_change_property) (ClientPtr client); 7390f2b693Smrgstatic int (*saved_delete_property) (ClientPtr client); 7490f2b693Smrg 75d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen); 76d6c0b56eSmrg 77d6c0b56eSmrgconst OptionInfoRec AMDGPUOptions_KMS[] = { 78d6c0b56eSmrg {OPTION_ACCEL, "Accel", OPTV_BOOLEAN, {0}, FALSE}, 79d6c0b56eSmrg {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, 80d6c0b56eSmrg {OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE}, 81d6c0b56eSmrg {OPTION_SUBPIXEL_ORDER, "SubPixelOrder", OPTV_ANYSTR, {0}, FALSE}, 82d6c0b56eSmrg {OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE}, 83d6c0b56eSmrg {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE}, 84d6c0b56eSmrg {OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE}, 85d6c0b56eSmrg {OPTION_DRI, "DRI", OPTV_INTEGER, {0}, FALSE}, 86d6c0b56eSmrg {OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE}, 87d6c0b56eSmrg {OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE}, 88d6c0b56eSmrg {OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE}, 8990f2b693Smrg {OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE }, 90e49c54bcSmrg {OPTION_ASYNC_FLIP_SECONDARIES, "AsyncFlipSecondaries", OPTV_BOOLEAN, {0}, FALSE}, 91d6c0b56eSmrg {-1, NULL, OPTV_NONE, {0}, FALSE} 92d6c0b56eSmrg}; 93d6c0b56eSmrg 94d6c0b56eSmrgconst OptionInfoRec *AMDGPUOptionsWeak(void) 95d6c0b56eSmrg{ 96d6c0b56eSmrg return AMDGPUOptions_KMS; 97d6c0b56eSmrg} 98d6c0b56eSmrg 9990f2b693Smrgstatic inline struct amdgpu_window_priv *get_window_priv(WindowPtr win) { 10090f2b693Smrg return dixLookupPrivate(&win->devPrivates, &amdgpu_window_private_key); 10190f2b693Smrg} 10290f2b693Smrg 10390f2b693Smrgstatic void 10490f2b693Smrgamdgpu_vrr_property_update(WindowPtr window, Bool variable_refresh) 10590f2b693Smrg{ 10690f2b693Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); 10790f2b693Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 10890f2b693Smrg 10990f2b693Smrg get_window_priv(window)->variable_refresh = variable_refresh; 11090f2b693Smrg 11190f2b693Smrg if (info->flip_window == window && 11290f2b693Smrg info->drmmode.present_flipping) 11390f2b693Smrg amdgpu_present_set_screen_vrr(scrn, variable_refresh); 11490f2b693Smrg} 11590f2b693Smrg 11690f2b693Smrg/* Wrapper for xserver/dix/property.c:ProcChangeProperty */ 11790f2b693Smrgstatic int 11890f2b693Smrgamdgpu_change_property(ClientPtr client) 11990f2b693Smrg{ 12090f2b693Smrg WindowPtr window; 12190f2b693Smrg int ret; 12290f2b693Smrg 12390f2b693Smrg REQUEST(xChangePropertyReq); 12490f2b693Smrg 12590f2b693Smrg client->requestVector[X_ChangeProperty] = saved_change_property; 12690f2b693Smrg ret = saved_change_property(client); 12790f2b693Smrg 12890f2b693Smrg if (restore_property_vector) 12990f2b693Smrg return ret; 13090f2b693Smrg 13190f2b693Smrg client->requestVector[X_ChangeProperty] = amdgpu_change_property; 13290f2b693Smrg 13390f2b693Smrg if (ret != Success) 13490f2b693Smrg return ret; 13590f2b693Smrg 13690f2b693Smrg ret = dixLookupWindow(&window, stuff->window, client, DixSetPropAccess); 13790f2b693Smrg if (ret != Success) 13890f2b693Smrg return ret; 13990f2b693Smrg 14090f2b693Smrg if (stuff->property == amdgpu_vrr_atom && 14190f2b693Smrg xf86ScreenToScrn(window->drawable.pScreen)->PreInit == 14290f2b693Smrg AMDGPUPreInit_KMS && stuff->format == 32 && stuff->nUnits == 1) { 14390f2b693Smrg uint32_t *value = (uint32_t*)(stuff + 1); 14490f2b693Smrg 14590f2b693Smrg amdgpu_vrr_property_update(window, *value != 0); 14690f2b693Smrg } 14790f2b693Smrg 14890f2b693Smrg return ret; 14990f2b693Smrg} 15090f2b693Smrg 15190f2b693Smrg/* Wrapper for xserver/dix/property.c:ProcDeleteProperty */ 15290f2b693Smrgstatic int 15390f2b693Smrgamdgpu_delete_property(ClientPtr client) 15490f2b693Smrg{ 15590f2b693Smrg WindowPtr window; 15690f2b693Smrg int ret; 15790f2b693Smrg 15890f2b693Smrg REQUEST(xDeletePropertyReq); 15990f2b693Smrg 16090f2b693Smrg client->requestVector[X_DeleteProperty] = saved_delete_property; 16190f2b693Smrg ret = saved_delete_property(client); 16290f2b693Smrg 16390f2b693Smrg if (restore_property_vector) 16490f2b693Smrg return ret; 16590f2b693Smrg 16690f2b693Smrg client->requestVector[X_DeleteProperty] = amdgpu_delete_property; 16790f2b693Smrg 16890f2b693Smrg if (ret != Success) 16990f2b693Smrg return ret; 17090f2b693Smrg 17190f2b693Smrg ret = dixLookupWindow(&window, stuff->window, client, DixSetPropAccess); 17290f2b693Smrg if (ret != Success) 17390f2b693Smrg return ret; 17490f2b693Smrg 17590f2b693Smrg if (stuff->property == amdgpu_vrr_atom && 17690f2b693Smrg xf86ScreenToScrn(window->drawable.pScreen)->PreInit == 17790f2b693Smrg AMDGPUPreInit_KMS) 17890f2b693Smrg amdgpu_vrr_property_update(window, FALSE); 17990f2b693Smrg 18090f2b693Smrg return ret; 18190f2b693Smrg} 18290f2b693Smrg 18390f2b693Smrgstatic void 18490f2b693Smrgamdgpu_unwrap_property_requests(ScrnInfoPtr scrn) 18590f2b693Smrg{ 18690f2b693Smrg int i; 18790f2b693Smrg 18890f2b693Smrg if (!amdgpu_property_vectors_wrapped) 18990f2b693Smrg return; 19090f2b693Smrg 19190f2b693Smrg if (ProcVector[X_ChangeProperty] == amdgpu_change_property) 19290f2b693Smrg ProcVector[X_ChangeProperty] = saved_change_property; 19390f2b693Smrg else 19490f2b693Smrg restore_property_vector = TRUE; 19590f2b693Smrg 19690f2b693Smrg if (ProcVector[X_DeleteProperty] == amdgpu_delete_property) 19790f2b693Smrg ProcVector[X_DeleteProperty] = saved_delete_property; 19890f2b693Smrg else 19990f2b693Smrg restore_property_vector = TRUE; 20090f2b693Smrg 20190f2b693Smrg for (i = 0; i < currentMaxClients; i++) { 20290f2b693Smrg if (clients[i]->requestVector[X_ChangeProperty] == 20390f2b693Smrg amdgpu_change_property) { 20490f2b693Smrg clients[i]->requestVector[X_ChangeProperty] = 20590f2b693Smrg saved_change_property; 20690f2b693Smrg } else { 20790f2b693Smrg restore_property_vector = TRUE; 20890f2b693Smrg } 20990f2b693Smrg 21090f2b693Smrg if (clients[i]->requestVector[X_DeleteProperty] == 21190f2b693Smrg amdgpu_delete_property) { 21290f2b693Smrg clients[i]->requestVector[X_DeleteProperty] = 21390f2b693Smrg saved_delete_property; 21490f2b693Smrg } else { 21590f2b693Smrg restore_property_vector = TRUE; 21690f2b693Smrg } 21790f2b693Smrg } 21890f2b693Smrg 21990f2b693Smrg if (restore_property_vector) { 22090f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 22190f2b693Smrg "Couldn't unwrap some window property request vectors\n"); 22290f2b693Smrg } 22390f2b693Smrg 22490f2b693Smrg amdgpu_property_vectors_wrapped = FALSE; 22590f2b693Smrg} 22690f2b693Smrg 227d6c0b56eSmrgextern _X_EXPORT int gAMDGPUEntityIndex; 228d6c0b56eSmrg 229d6c0b56eSmrgstatic int getAMDGPUEntityIndex(void) 230d6c0b56eSmrg{ 231d6c0b56eSmrg return gAMDGPUEntityIndex; 232d6c0b56eSmrg} 233d6c0b56eSmrg 234d6c0b56eSmrgAMDGPUEntPtr AMDGPUEntPriv(ScrnInfoPtr pScrn) 235d6c0b56eSmrg{ 236d6c0b56eSmrg DevUnion *pPriv; 237d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 238d6c0b56eSmrg pPriv = xf86GetEntityPrivate(info->pEnt->index, getAMDGPUEntityIndex()); 239d6c0b56eSmrg return pPriv->ptr; 240d6c0b56eSmrg} 241d6c0b56eSmrg 242d6c0b56eSmrg/* Allocate our private AMDGPUInfoRec */ 243d6c0b56eSmrgstatic Bool AMDGPUGetRec(ScrnInfoPtr pScrn) 244d6c0b56eSmrg{ 245d6c0b56eSmrg if (pScrn->driverPrivate) 246d6c0b56eSmrg return TRUE; 247d6c0b56eSmrg 248d6c0b56eSmrg pScrn->driverPrivate = xnfcalloc(sizeof(AMDGPUInfoRec), 1); 249d6c0b56eSmrg return TRUE; 250d6c0b56eSmrg} 251d6c0b56eSmrg 252d6c0b56eSmrg/* Free our private AMDGPUInfoRec */ 253d6c0b56eSmrgstatic void AMDGPUFreeRec(ScrnInfoPtr pScrn) 254d6c0b56eSmrg{ 255d6c0b56eSmrg DevUnion *pPriv; 256d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt; 257d6c0b56eSmrg AMDGPUInfoPtr info; 25824b90cf4Smrg EntityInfoPtr pEnt; 259d6c0b56eSmrg 260d6c0b56eSmrg if (!pScrn) 261d6c0b56eSmrg return; 262d6c0b56eSmrg 26390f2b693Smrg pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); 26490f2b693Smrg pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex); 26590f2b693Smrg pAMDGPUEnt = pPriv->ptr; 26690f2b693Smrg 267d6c0b56eSmrg info = AMDGPUPTR(pScrn); 26824b90cf4Smrg if (info) { 26990f2b693Smrg pAMDGPUEnt->scrn[info->instance_id] = NULL; 27090f2b693Smrg pAMDGPUEnt->num_scrns--; 27124b90cf4Smrg free(pScrn->driverPrivate); 27224b90cf4Smrg pScrn->driverPrivate = NULL; 27324b90cf4Smrg } 27424b90cf4Smrg 275d6c0b56eSmrg if (pAMDGPUEnt->fd > 0) { 276d6c0b56eSmrg DevUnion *pPriv; 277d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt; 278d6c0b56eSmrg pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 279d6c0b56eSmrg getAMDGPUEntityIndex()); 280d6c0b56eSmrg 281d6c0b56eSmrg pAMDGPUEnt = pPriv->ptr; 282d6c0b56eSmrg pAMDGPUEnt->fd_ref--; 283d6c0b56eSmrg if (!pAMDGPUEnt->fd_ref) { 28490f2b693Smrg amdgpu_unwrap_property_requests(pScrn); 285d6c0b56eSmrg amdgpu_device_deinitialize(pAMDGPUEnt->pDev); 28611bf0794Smrg amdgpu_kernel_close_fd(pAMDGPUEnt); 28746845023Smrg free(pAMDGPUEnt->busid); 28824b90cf4Smrg free(pPriv->ptr); 28924b90cf4Smrg pPriv->ptr = NULL; 290d6c0b56eSmrg } 291d6c0b56eSmrg } 292d6c0b56eSmrg 29324b90cf4Smrg free(pEnt); 294d6c0b56eSmrg} 295d6c0b56eSmrg 29690f2b693SmrgBool amdgpu_window_has_variable_refresh(WindowPtr win) { 29790f2b693Smrg struct amdgpu_window_priv *priv = get_window_priv(win); 29890f2b693Smrg 29990f2b693Smrg return priv->variable_refresh; 30090f2b693Smrg} 30190f2b693Smrg 302d6c0b56eSmrgstatic void *amdgpuShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, 303d6c0b56eSmrg int mode, CARD32 * size, void *closure) 304d6c0b56eSmrg{ 305d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 306d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 307d6c0b56eSmrg int stride; 308d6c0b56eSmrg 309d6c0b56eSmrg stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8; 310d6c0b56eSmrg *size = stride; 311d6c0b56eSmrg 312d6c0b56eSmrg return ((uint8_t *) info->front_buffer->cpu_ptr + row * stride + offset); 313d6c0b56eSmrg} 314d6c0b56eSmrg 315d6c0b56eSmrgstatic void 316d6c0b56eSmrgamdgpuUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) 317d6c0b56eSmrg{ 318d6c0b56eSmrg shadowUpdatePacked(pScreen, pBuf); 319d6c0b56eSmrg} 320d6c0b56eSmrg 321504d986fSmrgstatic Bool 322504d986fSmrgcallback_needs_flush(AMDGPUInfoPtr info, struct amdgpu_client_priv *client_priv) 323504d986fSmrg{ 324504d986fSmrg return (int)(client_priv->needs_flush - info->gpu_flushed) > 0; 325504d986fSmrg} 326504d986fSmrg 327504d986fSmrgstatic void 328504d986fSmrgamdgpu_event_callback(CallbackListPtr *list, 329504d986fSmrg pointer user_data, pointer call_data) 330504d986fSmrg{ 331504d986fSmrg EventInfoRec *eventinfo = call_data; 332504d986fSmrg ScrnInfoPtr pScrn = user_data; 333504d986fSmrg ScreenPtr pScreen = pScrn->pScreen; 334504d986fSmrg struct amdgpu_client_priv *client_priv = 335504d986fSmrg dixLookupScreenPrivate(&eventinfo->client->devPrivates, 336504d986fSmrg &amdgpu_client_private_key, pScreen); 337504d986fSmrg struct amdgpu_client_priv *server_priv = 338504d986fSmrg dixLookupScreenPrivate(&serverClient->devPrivates, 339504d986fSmrg &amdgpu_client_private_key, pScreen); 340504d986fSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 341504d986fSmrg int i; 342504d986fSmrg 343504d986fSmrg if (callback_needs_flush(info, client_priv) || 344504d986fSmrg callback_needs_flush(info, server_priv)) 345504d986fSmrg return; 346504d986fSmrg 347504d986fSmrg /* Don't let gpu_flushed get too far ahead of needs_flush, in order 348504d986fSmrg * to prevent false positives in callback_needs_flush() 349504d986fSmrg */ 350504d986fSmrg client_priv->needs_flush = info->gpu_flushed; 351504d986fSmrg server_priv->needs_flush = info->gpu_flushed; 352504d986fSmrg 353504d986fSmrg for (i = 0; i < eventinfo->count; i++) { 354504d986fSmrg if (eventinfo->events[i].u.u.type == info->callback_event_type) { 355504d986fSmrg client_priv->needs_flush++; 356504d986fSmrg server_priv->needs_flush++; 357504d986fSmrg return; 358504d986fSmrg } 359504d986fSmrg } 360504d986fSmrg} 361504d986fSmrg 362504d986fSmrgstatic void 363504d986fSmrgamdgpu_flush_callback(CallbackListPtr *list, 364504d986fSmrg pointer user_data, pointer call_data) 365504d986fSmrg{ 366504d986fSmrg ScrnInfoPtr pScrn = user_data; 367504d986fSmrg ScreenPtr pScreen = pScrn->pScreen; 368504d986fSmrg ClientPtr client = call_data ? call_data : serverClient; 369504d986fSmrg struct amdgpu_client_priv *client_priv = 370504d986fSmrg dixLookupScreenPrivate(&client->devPrivates, 371504d986fSmrg &amdgpu_client_private_key, pScreen); 372504d986fSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 373504d986fSmrg 374504d986fSmrg if (pScrn->vtSema && callback_needs_flush(info, client_priv)) 375504d986fSmrg amdgpu_glamor_flush(pScrn); 376504d986fSmrg} 377504d986fSmrg 378d6c0b56eSmrgstatic Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen) 379d6c0b56eSmrg{ 38011bf0794Smrg ExtensionEntry *damage_ext; 381d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 382d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 383d6c0b56eSmrg PixmapPtr pixmap; 384d6c0b56eSmrg 385d6c0b56eSmrg pScreen->CreateScreenResources = info->CreateScreenResources; 386d6c0b56eSmrg if (!(*pScreen->CreateScreenResources) (pScreen)) 387d6c0b56eSmrg return FALSE; 388d6c0b56eSmrg pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS; 389d6c0b56eSmrg 390d6c0b56eSmrg /* Set the RandR primary output if Xorg hasn't */ 391504d986fSmrg if (dixPrivateKeyRegistered(rrPrivKey)) { 392504d986fSmrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(pScreen); 393504d986fSmrg 39424b90cf4Smrg if (!pScreen->isGPU && !rrScrPriv->primaryOutput) { 395504d986fSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 396d6c0b56eSmrg 397504d986fSmrg rrScrPriv->primaryOutput = xf86_config->output[0]->randr_output; 398504d986fSmrg RROutputChanged(rrScrPriv->primaryOutput, FALSE); 399504d986fSmrg rrScrPriv->layoutChanged = TRUE; 400504d986fSmrg } 40190f2b693Smrg 40290f2b693Smrg drmmode_uevent_init(pScrn, &info->drmmode); 403d6c0b56eSmrg } 404d6c0b56eSmrg 40524b90cf4Smrg if (!drmmode_set_desired_modes(pScrn, &info->drmmode, pScreen->isGPU)) 406d6c0b56eSmrg return FALSE; 407d6c0b56eSmrg 408d6c0b56eSmrg if (info->shadow_fb) { 409d6c0b56eSmrg pixmap = pScreen->GetScreenPixmap(pScreen); 410d6c0b56eSmrg 411d6c0b56eSmrg if (!shadowAdd(pScreen, pixmap, amdgpuUpdatePacked, 412d6c0b56eSmrg amdgpuShadowWindow, 0, NULL)) 413d6c0b56eSmrg return FALSE; 414d6c0b56eSmrg } 415d6c0b56eSmrg 416d6c0b56eSmrg if (info->dri2.enabled || info->use_glamor) { 417d6c0b56eSmrg if (info->front_buffer) { 418d6c0b56eSmrg PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); 419504d986fSmrg 420504d986fSmrg if (!amdgpu_set_pixmap_bo(pPix, info->front_buffer)) 421504d986fSmrg return FALSE; 422d6c0b56eSmrg } 423d6c0b56eSmrg } 424d6c0b56eSmrg 425d6c0b56eSmrg if (info->use_glamor) 426d6c0b56eSmrg amdgpu_glamor_create_screen_resources(pScreen); 427d6c0b56eSmrg 428504d986fSmrg info->callback_event_type = -1; 42924b90cf4Smrg if (!pScreen->isGPU && (damage_ext = CheckExtension("DAMAGE"))) { 430504d986fSmrg info->callback_event_type = damage_ext->eventBase + XDamageNotify; 431504d986fSmrg 432504d986fSmrg if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn)) 433504d986fSmrg return FALSE; 434504d986fSmrg 435504d986fSmrg if (!AddCallback(&EventCallback, amdgpu_event_callback, pScrn)) { 436504d986fSmrg DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn); 437504d986fSmrg return FALSE; 438504d986fSmrg } 439504d986fSmrg 440504d986fSmrg if (!dixRegisterScreenPrivateKey(&amdgpu_client_private_key, pScreen, 441504d986fSmrg PRIVATE_CLIENT, sizeof(struct amdgpu_client_priv))) { 442504d986fSmrg DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn); 443504d986fSmrg DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn); 444504d986fSmrg return FALSE; 445504d986fSmrg } 446504d986fSmrg } 447504d986fSmrg 44890f2b693Smrg if (info->vrr_support && 44990f2b693Smrg !dixRegisterPrivateKey(&amdgpu_window_private_key, 45090f2b693Smrg PRIVATE_WINDOW, 45190f2b693Smrg sizeof(struct amdgpu_window_priv))) 45290f2b693Smrg return FALSE; 45390f2b693Smrg 454d6c0b56eSmrg return TRUE; 455d6c0b56eSmrg} 456d6c0b56eSmrg 457504d986fSmrgstatic Bool 458504d986fSmrgamdgpu_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents) 459504d986fSmrg{ 46011bf0794Smrg if (xf86_crtc->scrn->is_gpu) { 46111bf0794Smrg extents->x1 -= xf86_crtc->x; 46211bf0794Smrg extents->y1 -= xf86_crtc->y; 46311bf0794Smrg extents->x2 -= xf86_crtc->x; 46411bf0794Smrg extents->y2 -= xf86_crtc->y; 46524b90cf4Smrg } else { 46611bf0794Smrg extents->x1 -= xf86_crtc->filter_width >> 1; 46711bf0794Smrg extents->x2 += xf86_crtc->filter_width >> 1; 46811bf0794Smrg extents->y1 -= xf86_crtc->filter_height >> 1; 46911bf0794Smrg extents->y2 += xf86_crtc->filter_height >> 1; 47011bf0794Smrg pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, extents); 47111bf0794Smrg } 472504d986fSmrg 473504d986fSmrg extents->x1 = max(extents->x1, 0); 474504d986fSmrg extents->y1 = max(extents->y1, 0); 475504d986fSmrg extents->x2 = min(extents->x2, xf86_crtc->mode.HDisplay); 476504d986fSmrg extents->y2 = min(extents->y2, xf86_crtc->mode.VDisplay); 477504d986fSmrg 478504d986fSmrg return (extents->x1 < extents->x2 && extents->y1 < extents->y2); 479504d986fSmrg} 480504d986fSmrg 481504d986fSmrgstatic RegionPtr 482504d986fSmrgtransform_region(RegionPtr region, struct pict_f_transform *transform, 483504d986fSmrg int w, int h) 484504d986fSmrg{ 485504d986fSmrg BoxPtr boxes = RegionRects(region); 486504d986fSmrg int nboxes = RegionNumRects(region); 487504d986fSmrg xRectanglePtr rects = malloc(nboxes * sizeof(*rects)); 488504d986fSmrg RegionPtr transformed; 489504d986fSmrg int nrects = 0; 490504d986fSmrg BoxRec box; 491504d986fSmrg int i; 492504d986fSmrg 493504d986fSmrg for (i = 0; i < nboxes; i++) { 494504d986fSmrg box.x1 = boxes[i].x1; 495504d986fSmrg box.x2 = boxes[i].x2; 496504d986fSmrg box.y1 = boxes[i].y1; 497504d986fSmrg box.y2 = boxes[i].y2; 498504d986fSmrg pixman_f_transform_bounds(transform, &box); 499504d986fSmrg 500504d986fSmrg box.x1 = max(box.x1, 0); 501504d986fSmrg box.y1 = max(box.y1, 0); 502504d986fSmrg box.x2 = min(box.x2, w); 503504d986fSmrg box.y2 = min(box.y2, h); 504504d986fSmrg if (box.x1 >= box.x2 || box.y1 >= box.y2) 505504d986fSmrg continue; 506504d986fSmrg 507504d986fSmrg rects[nrects].x = box.x1; 508504d986fSmrg rects[nrects].y = box.y1; 509504d986fSmrg rects[nrects].width = box.x2 - box.x1; 510504d986fSmrg rects[nrects].height = box.y2 - box.y1; 511504d986fSmrg nrects++; 512504d986fSmrg } 513504d986fSmrg 514504d986fSmrg transformed = RegionFromRects(nrects, rects, CT_UNSORTED); 515504d986fSmrg free(rects); 516504d986fSmrg return transformed; 517504d986fSmrg} 518504d986fSmrg 519504d986fSmrgstatic void 520504d986fSmrgamdgpu_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region, 521504d986fSmrg int scanout_id) 522504d986fSmrg{ 523504d986fSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 52446845023Smrg DrawablePtr dst = &drmmode_crtc->scanout[scanout_id]->drawable; 52546845023Smrg DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1]->drawable; 526504d986fSmrg RegionPtr last_region = &drmmode_crtc->scanout_last_region; 527504d986fSmrg ScrnInfoPtr scrn = xf86_crtc->scrn; 528504d986fSmrg ScreenPtr pScreen = scrn->pScreen; 529504d986fSmrg RegionRec remaining; 530504d986fSmrg RegionPtr sync_region = NULL; 531504d986fSmrg BoxRec extents; 532504d986fSmrg GCPtr gc; 533504d986fSmrg 534504d986fSmrg if (RegionNil(last_region)) 535504d986fSmrg return; 536504d986fSmrg 537504d986fSmrg RegionNull(&remaining); 538504d986fSmrg RegionSubtract(&remaining, last_region, new_region); 539504d986fSmrg if (RegionNil(&remaining)) 540504d986fSmrg goto uninit; 541504d986fSmrg 542504d986fSmrg extents = *RegionExtents(&remaining); 543504d986fSmrg if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) 544504d986fSmrg goto uninit; 545504d986fSmrg 546504d986fSmrg if (xf86_crtc->driverIsPerformingTransform) { 547504d986fSmrg sync_region = transform_region(&remaining, 548504d986fSmrg &xf86_crtc->f_framebuffer_to_crtc, 549504d986fSmrg dst->width, dst->height); 55024b90cf4Smrg } else { 551504d986fSmrg sync_region = RegionDuplicate(&remaining); 552504d986fSmrg RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y); 553504d986fSmrg } 554504d986fSmrg 555504d986fSmrg gc = GetScratchGC(dst->depth, pScreen); 556504d986fSmrg if (gc) { 557504d986fSmrg gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0); 55811bf0794Smrg ValidateGC(dst, gc); 559504d986fSmrg sync_region = NULL; 560504d986fSmrg gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0); 561504d986fSmrg FreeScratchGC(gc); 562504d986fSmrg } 563504d986fSmrg 564504d986fSmrg uninit: 565504d986fSmrg if (sync_region) 566504d986fSmrg RegionDestroy(sync_region); 567504d986fSmrg RegionUninit(&remaining); 568504d986fSmrg} 569504d986fSmrg 57024b90cf4Smrgstatic void 57124b90cf4Smrgamdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data) 57224b90cf4Smrg{ 57324b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 57424b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 57590f2b693Smrg struct drmmode_fb *fb = event_data; 57624b90cf4Smrg 57735d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 57890f2b693Smrg 57990f2b693Smrg if (drmmode_crtc->flip_pending == fb) { 58090f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 58190f2b693Smrg NULL); 58290f2b693Smrg } 58324b90cf4Smrg} 58424b90cf4Smrg 58524b90cf4Smrgstatic void 58624b90cf4Smrgamdgpu_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec, 58724b90cf4Smrg void *event_data) 58824b90cf4Smrg{ 58924b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 59024b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 59190f2b693Smrg struct drmmode_fb *fb = event_data; 59224b90cf4Smrg 59390f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 59424b90cf4Smrg amdgpu_scanout_flip_abort(crtc, event_data); 59524b90cf4Smrg} 59624b90cf4Smrg 597504d986fSmrg 598504d986fSmrgstatic RegionPtr 599504d986fSmrgdirty_region(PixmapDirtyUpdatePtr dirty) 600d6c0b56eSmrg{ 601504d986fSmrg RegionPtr damageregion = DamageRegion(dirty->damage); 602504d986fSmrg RegionPtr dstregion; 603504d986fSmrg 604504d986fSmrg#ifdef HAS_DIRTYTRACKING_ROTATION 605504d986fSmrg if (dirty->rotation != RR_Rotate_0) { 606504d986fSmrg dstregion = transform_region(damageregion, 607504d986fSmrg &dirty->f_inverse, 60846845023Smrg dirty->secondary_dst->drawable.width, 60946845023Smrg dirty->secondary_dst->drawable.height); 610504d986fSmrg } else 611504d986fSmrg#endif 612504d986fSmrg { 613504d986fSmrg RegionRec pixregion; 614504d986fSmrg 615504d986fSmrg dstregion = RegionDuplicate(damageregion); 616504d986fSmrg RegionTranslate(dstregion, -dirty->x, -dirty->y); 61746845023Smrg PixmapRegionInit(&pixregion, dirty->secondary_dst); 618504d986fSmrg RegionIntersect(dstregion, dstregion, &pixregion); 619504d986fSmrg RegionUninit(&pixregion); 620504d986fSmrg } 621504d986fSmrg 622504d986fSmrg return dstregion; 623504d986fSmrg} 624504d986fSmrg 625504d986fSmrgstatic void 626504d986fSmrgredisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region) 627504d986fSmrg{ 62824b90cf4Smrg ScrnInfoPtr src_scrn = 62924b90cf4Smrg xf86ScreenToScrn(amdgpu_dirty_src_drawable(dirty)->pScreen); 630504d986fSmrg 631504d986fSmrg if (RegionNil(region)) 632504d986fSmrg goto out; 633504d986fSmrg 63446845023Smrg if (dirty->secondary_dst->primary_pixmap) 63546845023Smrg DamageRegionAppend(&dirty->secondary_dst->drawable, region); 636d6c0b56eSmrg 637d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION 638d6c0b56eSmrg PixmapSyncDirtyHelper(dirty); 639d6c0b56eSmrg#else 640504d986fSmrg PixmapSyncDirtyHelper(dirty, region); 641d6c0b56eSmrg#endif 642d6c0b56eSmrg 64324b90cf4Smrg amdgpu_glamor_flush(src_scrn); 64446845023Smrg if (dirty->secondary_dst->primary_pixmap) 64546845023Smrg DamageRegionProcessPending(&dirty->secondary_dst->drawable); 646504d986fSmrg 647504d986fSmrgout: 648504d986fSmrg DamageEmpty(dirty->damage); 649d6c0b56eSmrg} 650d6c0b56eSmrg 651504d986fSmrgstatic void 652504d986fSmrgamdgpu_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data) 653d6c0b56eSmrg{ 654504d986fSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 655504d986fSmrg 65635d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 657504d986fSmrg} 658504d986fSmrg 659504d986fSmrgvoid 660504d986fSmrgamdgpu_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty) 661504d986fSmrg{ 66246845023Smrg ScreenPtr primary_screen = amdgpu_dirty_primary(dirty); 663d6c0b56eSmrg PixmapDirtyUpdatePtr ent; 664504d986fSmrg RegionPtr region; 665d6c0b56eSmrg 66646845023Smrg xorg_list_for_each_entry(ent, &primary_screen->pixmap_dirty_list, ent) { 66746845023Smrg if (!amdgpu_dirty_src_equals(dirty, ent->secondary_dst)) 668504d986fSmrg continue; 669d6c0b56eSmrg 670504d986fSmrg region = dirty_region(ent); 671504d986fSmrg redisplay_dirty(ent, region); 672504d986fSmrg RegionDestroy(region); 673d6c0b56eSmrg } 674d6c0b56eSmrg} 675504d986fSmrg 676504d986fSmrg 677504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP 678d6c0b56eSmrg 679d6c0b56eSmrgstatic Bool 68046845023Smrgprimary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) 681d6c0b56eSmrg{ 68246845023Smrg ScreenPtr primary_screen = amdgpu_dirty_primary(dirty); 683504d986fSmrg 68446845023Smrg return primary_screen->SyncSharedPixmap != NULL; 685504d986fSmrg} 686504d986fSmrg 687504d986fSmrgstatic Bool 68846845023Smrgsecondary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) 689504d986fSmrg{ 69046845023Smrg ScreenPtr secondary_screen = dirty->secondary_dst->drawable.pScreen; 691504d986fSmrg 69246845023Smrg return secondary_screen->SyncSharedPixmap != NULL; 693504d986fSmrg} 694504d986fSmrg 695504d986fSmrgstatic void 696504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty) 697504d986fSmrg{ 69846845023Smrg ScreenPtr primary_screen = amdgpu_dirty_primary(dirty); 699504d986fSmrg 70046845023Smrg primary_screen->SyncSharedPixmap(dirty); 701504d986fSmrg} 702504d986fSmrg 703504d986fSmrg#else /* !HAS_SYNC_SHARED_PIXMAP */ 704504d986fSmrg 705504d986fSmrgstatic Bool 70646845023Smrgprimary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) 707504d986fSmrg{ 70846845023Smrg ScrnInfoPtr primary_scrn = xf86ScreenToScrn(amdgpu_dirty_primary(dirty)); 709504d986fSmrg 71046845023Smrg return primary_scrn->driverName == scrn->driverName; 711504d986fSmrg} 712504d986fSmrg 713504d986fSmrgstatic Bool 71446845023Smrgsecondary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) 715504d986fSmrg{ 71646845023Smrg ScrnInfoPtr secondary_scrn = xf86ScreenToScrn(dirty->secondary_dst->drawable.pScreen); 717504d986fSmrg 71846845023Smrg return secondary_scrn->driverName == scrn->driverName; 719504d986fSmrg} 720504d986fSmrg 721504d986fSmrgstatic void 722504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty) 723504d986fSmrg{ 724504d986fSmrg amdgpu_sync_shared_pixmap(dirty); 725504d986fSmrg} 726504d986fSmrg 727504d986fSmrg#endif /* HAS_SYNC_SHARED_PIXMAPS */ 728504d986fSmrg 729504d986fSmrg 73011bf0794Smrgstatic xf86CrtcPtr 73111bf0794Smrgamdgpu_prime_dirty_to_crtc(PixmapDirtyUpdatePtr dirty) 73211bf0794Smrg{ 73346845023Smrg ScreenPtr screen = dirty->secondary_dst->drawable.pScreen; 73411bf0794Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 73511bf0794Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 73611bf0794Smrg int c; 73711bf0794Smrg 73846845023Smrg /* Find the CRTC which is scanning out from this secondary pixmap */ 73911bf0794Smrg for (c = 0; c < xf86_config->num_crtc; c++) { 74011bf0794Smrg xf86CrtcPtr xf86_crtc = xf86_config->crtc[c]; 74111bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 74211bf0794Smrg 74324b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) 74411bf0794Smrg return xf86_crtc; 74511bf0794Smrg } 74611bf0794Smrg 74711bf0794Smrg return NULL; 74811bf0794Smrg} 74911bf0794Smrg 750504d986fSmrgstatic Bool 751504d986fSmrgamdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id) 752504d986fSmrg{ 753504d986fSmrg ScrnInfoPtr scrn = crtc->scrn; 754504d986fSmrg ScreenPtr screen = scrn->pScreen; 755504d986fSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 756504d986fSmrg PixmapDirtyUpdatePtr dirty; 757504d986fSmrg Bool ret = FALSE; 758504d986fSmrg 759504d986fSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 76024b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 761504d986fSmrg RegionPtr region; 762504d986fSmrg 76346845023Smrg if (primary_has_sync_shared_pixmap(scrn, dirty)) 764504d986fSmrg call_sync_shared_pixmap(dirty); 765504d986fSmrg 766504d986fSmrg region = dirty_region(dirty); 767504d986fSmrg if (RegionNil(region)) 768504d986fSmrg goto destroy; 769504d986fSmrg 77011bf0794Smrg if (drmmode_crtc->tear_free) { 771504d986fSmrg RegionTranslate(region, crtc->x, crtc->y); 772504d986fSmrg amdgpu_sync_scanout_pixmaps(crtc, region, scanout_id); 773504d986fSmrg amdgpu_glamor_flush(scrn); 774504d986fSmrg RegionCopy(&drmmode_crtc->scanout_last_region, region); 775504d986fSmrg RegionTranslate(region, -crtc->x, -crtc->y); 77646845023Smrg dirty->secondary_dst = drmmode_crtc->scanout[scanout_id]; 777504d986fSmrg } 778504d986fSmrg 779504d986fSmrg redisplay_dirty(dirty, region); 780504d986fSmrg ret = TRUE; 781504d986fSmrg destroy: 782504d986fSmrg RegionDestroy(region); 783504d986fSmrg break; 784504d986fSmrg } 785d6c0b56eSmrg } 786d6c0b56eSmrg 787504d986fSmrg return ret; 788504d986fSmrg} 789504d986fSmrg 79011bf0794Smrgstatic void 791504d986fSmrgamdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 792504d986fSmrg void *event_data) 793504d986fSmrg{ 794504d986fSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 795504d986fSmrg 796504d986fSmrg amdgpu_prime_scanout_do_update(crtc, 0); 79735d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 798504d986fSmrg} 799504d986fSmrg 800504d986fSmrgstatic void 801504d986fSmrgamdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty) 802504d986fSmrg{ 80346845023Smrg ScreenPtr screen = dirty->secondary_dst->drawable.pScreen; 804504d986fSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 80590f2b693Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 80611bf0794Smrg xf86CrtcPtr xf86_crtc = amdgpu_prime_dirty_to_crtc(dirty); 80711bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc; 808504d986fSmrg uintptr_t drm_queue_seq; 809504d986fSmrg 81011bf0794Smrg if (!xf86_crtc || !xf86_crtc->enabled) 81111bf0794Smrg return; 812504d986fSmrg 81311bf0794Smrg drmmode_crtc = xf86_crtc->driver_private; 81411bf0794Smrg if (drmmode_crtc->scanout_update_pending || 81546845023Smrg !drmmode_crtc->scanout[drmmode_crtc->scanout_id] || 81624b90cf4Smrg drmmode_crtc->dpms_mode != DPMSModeOn) 817504d986fSmrg return; 818504d986fSmrg 819504d986fSmrg drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc, 820504d986fSmrg AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, 821504d986fSmrg AMDGPU_DRM_QUEUE_ID_DEFAULT, NULL, 822504d986fSmrg amdgpu_prime_scanout_update_handler, 82390f2b693Smrg amdgpu_prime_scanout_update_abort, 82490f2b693Smrg FALSE); 825504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 826504d986fSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 827504d986fSmrg "amdgpu_drm_queue_alloc failed for PRIME update\n"); 82890f2b693Smrg amdgpu_prime_scanout_update_handler(xf86_crtc, 0, 0, NULL); 829504d986fSmrg return; 830504d986fSmrg } 831504d986fSmrg 83290f2b693Smrg drmmode_crtc->scanout_update_pending = drm_queue_seq; 83390f2b693Smrg 83424b90cf4Smrg if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, 83524b90cf4Smrg 1, drm_queue_seq, NULL, NULL)) { 83690f2b693Smrg if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) { 83790f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 83890f2b693Smrg "drmmode_wait_vblank failed for PRIME update: %s\n", 83990f2b693Smrg strerror(errno)); 84090f2b693Smrg drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED; 84190f2b693Smrg } 84290f2b693Smrg 84390f2b693Smrg drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd, 84490f2b693Smrg 0, 0, 0, 84590f2b693Smrg (void*)drm_queue_seq); 84690f2b693Smrg drmmode_crtc->wait_flip_nesting_level++; 84790f2b693Smrg amdgpu_drm_queue_handle_deferred(xf86_crtc); 848504d986fSmrg return; 849504d986fSmrg } 850504d986fSmrg 85190f2b693Smrg if (drmmode_crtc->scanout_status == 85290f2b693Smrg (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) { 85390f2b693Smrg /* The page flip and vblank ioctls failed before, but the vblank 85490f2b693Smrg * ioctl is working again, so we can try re-enabling TearFree 85590f2b693Smrg */ 85690f2b693Smrg xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode, 85790f2b693Smrg xf86_crtc->rotation, 85890f2b693Smrg xf86_crtc->x, xf86_crtc->y); 85990f2b693Smrg } 86090f2b693Smrg 86190f2b693Smrg drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED; 862504d986fSmrg} 863504d986fSmrg 864504d986fSmrgstatic void 865504d986fSmrgamdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent) 866504d986fSmrg{ 86746845023Smrg ScreenPtr screen = ent->secondary_dst->drawable.pScreen; 868504d986fSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 869504d986fSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 87011bf0794Smrg xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent); 87111bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc; 872504d986fSmrg uintptr_t drm_queue_seq; 873504d986fSmrg unsigned scanout_id; 87490f2b693Smrg struct drmmode_fb *fb; 875504d986fSmrg 87611bf0794Smrg if (!crtc || !crtc->enabled) 87711bf0794Smrg return; 878504d986fSmrg 87911bf0794Smrg drmmode_crtc = crtc->driver_private; 88090f2b693Smrg scanout_id = drmmode_crtc->scanout_id ^ 1; 88111bf0794Smrg if (drmmode_crtc->scanout_update_pending || 88246845023Smrg !drmmode_crtc->scanout[scanout_id] || 88324b90cf4Smrg drmmode_crtc->dpms_mode != DPMSModeOn) 884504d986fSmrg return; 885504d986fSmrg 886504d986fSmrg if (!amdgpu_prime_scanout_do_update(crtc, scanout_id)) 887504d986fSmrg return; 888504d986fSmrg 88946845023Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]); 89090f2b693Smrg if (!fb) { 89190f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 89290f2b693Smrg "Failed to get FB for PRIME flip.\n"); 89390f2b693Smrg return; 89490f2b693Smrg } 89590f2b693Smrg 896504d986fSmrg drm_queue_seq = amdgpu_drm_queue_alloc(crtc, 897504d986fSmrg AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, 89890f2b693Smrg AMDGPU_DRM_QUEUE_ID_DEFAULT, fb, 89924b90cf4Smrg amdgpu_scanout_flip_handler, 90090f2b693Smrg amdgpu_scanout_flip_abort, TRUE); 901504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 902504d986fSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 903504d986fSmrg "Allocating DRM event queue entry failed for PRIME flip.\n"); 904504d986fSmrg return; 905504d986fSmrg } 906504d986fSmrg 90790f2b693Smrg if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc, 90890f2b693Smrg fb->handle, 0, drm_queue_seq, 1) 90990f2b693Smrg != 0) { 91090f2b693Smrg if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) { 91190f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 91290f2b693Smrg "flip queue failed in %s: %s, TearFree inactive\n", 91390f2b693Smrg __func__, strerror(errno)); 91490f2b693Smrg drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED; 91590f2b693Smrg } 91690f2b693Smrg 91724b90cf4Smrg amdgpu_drm_abort_entry(drm_queue_seq); 91824b90cf4Smrg return; 91924b90cf4Smrg } 92024b90cf4Smrg 92190f2b693Smrg if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) { 92290f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n"); 92390f2b693Smrg drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED; 924504d986fSmrg } 925504d986fSmrg 926504d986fSmrg drmmode_crtc->scanout_id = scanout_id; 92735d5b7c7Smrg drmmode_crtc->scanout_update_pending = drm_queue_seq; 92890f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb); 929504d986fSmrg} 930504d986fSmrg 931504d986fSmrgstatic void 932504d986fSmrgamdgpu_dirty_update(ScrnInfoPtr scrn) 933504d986fSmrg{ 934504d986fSmrg ScreenPtr screen = scrn->pScreen; 935504d986fSmrg PixmapDirtyUpdatePtr ent; 936504d986fSmrg RegionPtr region; 937504d986fSmrg 938504d986fSmrg xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { 939504d986fSmrg if (screen->isGPU) { 940504d986fSmrg PixmapDirtyUpdatePtr region_ent = ent; 941504d986fSmrg 94246845023Smrg if (primary_has_sync_shared_pixmap(scrn, ent)) { 94346845023Smrg ScreenPtr primary_screen = amdgpu_dirty_primary(ent); 944504d986fSmrg 94546845023Smrg xorg_list_for_each_entry(region_ent, &primary_screen->pixmap_dirty_list, ent) { 94646845023Smrg if (amdgpu_dirty_src_equals(ent, region_ent->secondary_dst)) 947504d986fSmrg break; 948504d986fSmrg } 949504d986fSmrg } 950504d986fSmrg 951504d986fSmrg region = dirty_region(region_ent); 952504d986fSmrg 953504d986fSmrg if (RegionNotEmpty(region)) { 95411bf0794Smrg xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent); 95511bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = NULL; 95611bf0794Smrg 95711bf0794Smrg if (crtc) 95811bf0794Smrg drmmode_crtc = crtc->driver_private; 95911bf0794Smrg 96011bf0794Smrg if (drmmode_crtc && drmmode_crtc->tear_free) 961504d986fSmrg amdgpu_prime_scanout_flip(ent); 962504d986fSmrg else 963504d986fSmrg amdgpu_prime_scanout_update(ent); 964504d986fSmrg } else { 965504d986fSmrg DamageEmpty(region_ent->damage); 966504d986fSmrg } 967504d986fSmrg 968504d986fSmrg RegionDestroy(region); 969504d986fSmrg } else { 97046845023Smrg if (secondary_has_sync_shared_pixmap(scrn, ent)) 971504d986fSmrg continue; 972504d986fSmrg 973504d986fSmrg region = dirty_region(ent); 974504d986fSmrg redisplay_dirty(ent, region); 975504d986fSmrg RegionDestroy(region); 976504d986fSmrg } 977504d986fSmrg } 978504d986fSmrg} 97924b90cf4Smrg 98046845023Smrgstatic void 98146845023SmrgamdgpuSourceValidate(DrawablePtr draw, int x, int y, int w, int h, 98246845023Smrg unsigned int subWindowMode) 98346845023Smrg{ 98446845023Smrg} 985504d986fSmrg 98611bf0794SmrgBool 98724b90cf4Smrgamdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id, 98835d5b7c7Smrg PixmapPtr src_pix, BoxRec extents) 989d6c0b56eSmrg{ 990d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 99135d5b7c7Smrg RegionRec region = { .extents = extents, .data = NULL }; 992504d986fSmrg ScrnInfoPtr scrn = xf86_crtc->scrn; 993504d986fSmrg ScreenPtr pScreen = scrn->pScreen; 994d6c0b56eSmrg DrawablePtr pDraw; 995d6c0b56eSmrg 996d6c0b56eSmrg if (!xf86_crtc->enabled || 99746845023Smrg !drmmode_crtc->scanout[scanout_id] || 99835d5b7c7Smrg extents.x1 >= extents.x2 || extents.y1 >= extents.y2) 999d6c0b56eSmrg return FALSE; 1000d6c0b56eSmrg 100146845023Smrg pDraw = &drmmode_crtc->scanout[scanout_id]->drawable; 100235d5b7c7Smrg if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) 1003d6c0b56eSmrg return FALSE; 1004d6c0b56eSmrg 100511bf0794Smrg if (drmmode_crtc->tear_free) { 100624b90cf4Smrg amdgpu_sync_scanout_pixmaps(xf86_crtc, ®ion, scanout_id); 100724b90cf4Smrg RegionCopy(&drmmode_crtc->scanout_last_region, ®ion); 1008504d986fSmrg } 1009504d986fSmrg 1010d6c0b56eSmrg if (xf86_crtc->driverIsPerformingTransform) { 1011d6c0b56eSmrg SourceValidateProcPtr SourceValidate = pScreen->SourceValidate; 1012d6c0b56eSmrg PictFormatPtr format = PictureWindowFormat(pScreen->root); 1013d6c0b56eSmrg int error; 1014d6c0b56eSmrg PicturePtr src, dst; 1015d6c0b56eSmrg 101624b90cf4Smrg src = CreatePicture(None, &src_pix->drawable, format, 0L, NULL, 101724b90cf4Smrg serverClient, &error); 1018d6c0b56eSmrg if (!src) { 1019d6c0b56eSmrg ErrorF("Failed to create source picture for transformed scanout " 1020d6c0b56eSmrg "update\n"); 1021d6c0b56eSmrg goto out; 1022d6c0b56eSmrg } 1023d6c0b56eSmrg 1024d6c0b56eSmrg dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error); 1025d6c0b56eSmrg if (!dst) { 1026d6c0b56eSmrg ErrorF("Failed to create destination picture for transformed scanout " 1027d6c0b56eSmrg "update\n"); 1028d6c0b56eSmrg goto free_src; 1029d6c0b56eSmrg } 1030d6c0b56eSmrg error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer); 1031d6c0b56eSmrg if (error) { 1032d6c0b56eSmrg ErrorF("SetPictureTransform failed for transformed scanout " 1033d6c0b56eSmrg "update\n"); 1034d6c0b56eSmrg goto free_dst; 1035d6c0b56eSmrg } 1036d6c0b56eSmrg 1037d6c0b56eSmrg if (xf86_crtc->filter) 1038d6c0b56eSmrg SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params, 1039d6c0b56eSmrg xf86_crtc->nparams); 1040d6c0b56eSmrg 104146845023Smrg pScreen->SourceValidate = amdgpuSourceValidate; 1042d6c0b56eSmrg CompositePicture(PictOpSrc, 1043d6c0b56eSmrg src, NULL, dst, 104435d5b7c7Smrg extents.x1, extents.y1, 0, 0, extents.x1, 104535d5b7c7Smrg extents.y1, extents.x2 - extents.x1, 104635d5b7c7Smrg extents.y2 - extents.y1); 1047d6c0b56eSmrg pScreen->SourceValidate = SourceValidate; 1048d6c0b56eSmrg 1049d6c0b56eSmrg free_dst: 1050d6c0b56eSmrg FreePicture(dst, None); 1051d6c0b56eSmrg free_src: 1052d6c0b56eSmrg FreePicture(src, None); 1053d6c0b56eSmrg } else 1054d6c0b56eSmrg out: 1055d6c0b56eSmrg { 1056d6c0b56eSmrg GCPtr gc = GetScratchGC(pDraw->depth, pScreen); 1057d6c0b56eSmrg 1058d6c0b56eSmrg ValidateGC(pDraw, gc); 105924b90cf4Smrg (*gc->ops->CopyArea)(&src_pix->drawable, pDraw, gc, 106035d5b7c7Smrg xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1, 106135d5b7c7Smrg extents.x2 - extents.x1, extents.y2 - extents.y1, 106235d5b7c7Smrg extents.x1, extents.y1); 1063d6c0b56eSmrg FreeScratchGC(gc); 1064d6c0b56eSmrg } 1065d6c0b56eSmrg 1066d6c0b56eSmrg return TRUE; 1067d6c0b56eSmrg} 1068d6c0b56eSmrg 1069d6c0b56eSmrgstatic void 1070d6c0b56eSmrgamdgpu_scanout_update_abort(xf86CrtcPtr crtc, void *event_data) 1071d6c0b56eSmrg{ 1072d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = event_data; 1073d6c0b56eSmrg 107435d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 1075d6c0b56eSmrg} 1076d6c0b56eSmrg 107711bf0794Smrgstatic void 1078d6c0b56eSmrgamdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 1079d6c0b56eSmrg void *event_data) 1080d6c0b56eSmrg{ 108124b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = event_data; 108224b90cf4Smrg ScreenPtr screen = crtc->scrn->pScreen; 108324b90cf4Smrg RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage); 108424b90cf4Smrg 108524b90cf4Smrg if (crtc->enabled && 108624b90cf4Smrg !drmmode_crtc->flip_pending && 108724b90cf4Smrg drmmode_crtc->dpms_mode == DPMSModeOn) { 108824b90cf4Smrg if (amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id, 108924b90cf4Smrg screen->GetWindowPixmap(screen->root), 109035d5b7c7Smrg region->extents)) { 109135d5b7c7Smrg amdgpu_glamor_flush(crtc->scrn); 109224b90cf4Smrg RegionEmpty(region); 109335d5b7c7Smrg } 109424b90cf4Smrg } 1095d6c0b56eSmrg 1096d6c0b56eSmrg amdgpu_scanout_update_abort(crtc, event_data); 1097d6c0b56eSmrg} 1098d6c0b56eSmrg 1099d6c0b56eSmrgstatic void 1100d6c0b56eSmrgamdgpu_scanout_update(xf86CrtcPtr xf86_crtc) 1101d6c0b56eSmrg{ 1102d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 110390f2b693Smrg ScrnInfoPtr scrn = xf86_crtc->scrn; 110490f2b693Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 1105d6c0b56eSmrg uintptr_t drm_queue_seq; 1106d6c0b56eSmrg DamagePtr pDamage; 1107d6c0b56eSmrg RegionPtr pRegion; 1108d6c0b56eSmrg BoxRec extents; 1109d6c0b56eSmrg 1110d6c0b56eSmrg if (!xf86_crtc->enabled || 1111d6c0b56eSmrg drmmode_crtc->scanout_update_pending || 111224b90cf4Smrg drmmode_crtc->flip_pending || 111324b90cf4Smrg drmmode_crtc->dpms_mode != DPMSModeOn) 1114d6c0b56eSmrg return; 1115d6c0b56eSmrg 1116504d986fSmrg pDamage = drmmode_crtc->scanout_damage; 1117d6c0b56eSmrg if (!pDamage) 1118d6c0b56eSmrg return; 1119d6c0b56eSmrg 1120d6c0b56eSmrg pRegion = DamageRegion(pDamage); 1121d6c0b56eSmrg if (!RegionNotEmpty(pRegion)) 1122d6c0b56eSmrg return; 1123d6c0b56eSmrg 1124d6c0b56eSmrg extents = *RegionExtents(pRegion); 1125504d986fSmrg if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) { 1126504d986fSmrg RegionEmpty(pRegion); 1127d6c0b56eSmrg return; 1128504d986fSmrg } 1129d6c0b56eSmrg 1130d6c0b56eSmrg drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc, 1131d6c0b56eSmrg AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, 1132d6c0b56eSmrg AMDGPU_DRM_QUEUE_ID_DEFAULT, 1133d6c0b56eSmrg drmmode_crtc, 1134d6c0b56eSmrg amdgpu_scanout_update_handler, 113590f2b693Smrg amdgpu_scanout_update_abort, 113690f2b693Smrg FALSE); 1137504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 1138d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1139d6c0b56eSmrg "amdgpu_drm_queue_alloc failed for scanout update\n"); 114090f2b693Smrg amdgpu_scanout_update_handler(xf86_crtc, 0, 0, drmmode_crtc); 1141d6c0b56eSmrg return; 1142d6c0b56eSmrg } 1143d6c0b56eSmrg 114490f2b693Smrg drmmode_crtc->scanout_update_pending = drm_queue_seq; 114590f2b693Smrg 114624b90cf4Smrg if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, 114724b90cf4Smrg 1, drm_queue_seq, NULL, NULL)) { 114890f2b693Smrg if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) { 114990f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 115090f2b693Smrg "drmmode_wait_vblank failed for scanout update: %s\n", 115190f2b693Smrg strerror(errno)); 115290f2b693Smrg drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED; 115390f2b693Smrg } 115490f2b693Smrg 115590f2b693Smrg drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd, 115690f2b693Smrg 0, 0, 0, 115790f2b693Smrg (void*)drm_queue_seq); 115890f2b693Smrg drmmode_crtc->wait_flip_nesting_level++; 115990f2b693Smrg amdgpu_drm_queue_handle_deferred(xf86_crtc); 1160d6c0b56eSmrg return; 1161d6c0b56eSmrg } 1162d6c0b56eSmrg 116390f2b693Smrg if (drmmode_crtc->scanout_status == 116490f2b693Smrg (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) { 116590f2b693Smrg /* The page flip and vblank ioctls failed before, but the vblank 116690f2b693Smrg * ioctl is working again, so we can try re-enabling TearFree 116790f2b693Smrg */ 116890f2b693Smrg xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode, 116990f2b693Smrg xf86_crtc->rotation, 117090f2b693Smrg xf86_crtc->x, xf86_crtc->y); 117190f2b693Smrg } 117290f2b693Smrg 117390f2b693Smrg drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED; 1174d6c0b56eSmrg} 1175d6c0b56eSmrg 1176d6c0b56eSmrgstatic void 1177d6c0b56eSmrgamdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info, 1178d6c0b56eSmrg xf86CrtcPtr xf86_crtc) 1179d6c0b56eSmrg{ 1180d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; 118124b90cf4Smrg RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage); 118211bf0794Smrg ScrnInfoPtr scrn = xf86_crtc->scrn; 118311bf0794Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 1184d6c0b56eSmrg uintptr_t drm_queue_seq; 1185d6c0b56eSmrg unsigned scanout_id; 118690f2b693Smrg struct drmmode_fb *fb; 1187d6c0b56eSmrg 118811bf0794Smrg if (drmmode_crtc->scanout_update_pending || 118924b90cf4Smrg drmmode_crtc->flip_pending || 119024b90cf4Smrg drmmode_crtc->dpms_mode != DPMSModeOn) 1191d6c0b56eSmrg return; 1192d6c0b56eSmrg 1193d6c0b56eSmrg scanout_id = drmmode_crtc->scanout_id ^ 1; 119424b90cf4Smrg if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id, 119524b90cf4Smrg pScreen->GetWindowPixmap(pScreen->root), 119635d5b7c7Smrg region->extents)) 1197d6c0b56eSmrg return; 119835d5b7c7Smrg 119935d5b7c7Smrg amdgpu_glamor_flush(scrn); 120024b90cf4Smrg RegionEmpty(region); 1201d6c0b56eSmrg 120246845023Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]); 120390f2b693Smrg if (!fb) { 120490f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 120590f2b693Smrg "Failed to get FB for scanout flip.\n"); 120690f2b693Smrg return; 120790f2b693Smrg } 120890f2b693Smrg 1209d6c0b56eSmrg drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc, 1210d6c0b56eSmrg AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, 121190f2b693Smrg AMDGPU_DRM_QUEUE_ID_DEFAULT, fb, 121224b90cf4Smrg amdgpu_scanout_flip_handler, 121390f2b693Smrg amdgpu_scanout_flip_abort, TRUE); 1214504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 1215d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1216d6c0b56eSmrg "Allocating DRM event queue entry failed.\n"); 1217d6c0b56eSmrg return; 1218d6c0b56eSmrg } 1219d6c0b56eSmrg 122011bf0794Smrg if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc, 122190f2b693Smrg fb->handle, 0, drm_queue_seq, 1) 122290f2b693Smrg != 0) { 122390f2b693Smrg if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) { 122490f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 122590f2b693Smrg "flip queue failed in %s: %s, TearFree inactive\n", 122690f2b693Smrg __func__, strerror(errno)); 122790f2b693Smrg drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED; 122890f2b693Smrg } 122990f2b693Smrg 123011bf0794Smrg amdgpu_drm_abort_entry(drm_queue_seq); 123124b90cf4Smrg RegionCopy(DamageRegion(drmmode_crtc->scanout_damage), 123224b90cf4Smrg &drmmode_crtc->scanout_last_region); 123324b90cf4Smrg RegionEmpty(&drmmode_crtc->scanout_last_region); 123424b90cf4Smrg amdgpu_scanout_update(xf86_crtc); 123546845023Smrg drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[scanout_id]); 123624b90cf4Smrg drmmode_crtc->tear_free = FALSE; 1237d6c0b56eSmrg return; 1238d6c0b56eSmrg } 1239d6c0b56eSmrg 124090f2b693Smrg if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) { 124190f2b693Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n"); 124290f2b693Smrg drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED; 124390f2b693Smrg } 124490f2b693Smrg 1245d6c0b56eSmrg drmmode_crtc->scanout_id = scanout_id; 124635d5b7c7Smrg drmmode_crtc->scanout_update_pending = drm_queue_seq; 124790f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb); 1248d6c0b56eSmrg} 1249d6c0b56eSmrg 1250d6c0b56eSmrgstatic void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) 1251d6c0b56eSmrg{ 1252d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1253d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1254d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1255d6c0b56eSmrg int c; 1256d6c0b56eSmrg 1257d6c0b56eSmrg pScreen->BlockHandler = info->BlockHandler; 1258d6c0b56eSmrg (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); 1259d6c0b56eSmrg pScreen->BlockHandler = AMDGPUBlockHandler_KMS; 1260d6c0b56eSmrg 126146845023Smrg if (!xf86ScreenToScrn(amdgpu_primary_screen(pScreen))->vtSema) 126224b90cf4Smrg return; 126324b90cf4Smrg 126424b90cf4Smrg if (!pScreen->isGPU) 1265504d986fSmrg { 1266504d986fSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 126711bf0794Smrg xf86CrtcPtr crtc = xf86_config->crtc[c]; 126811bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 126911bf0794Smrg 127046845023Smrg if (drmmode_crtc->rotate) 127135d5b7c7Smrg continue; 127235d5b7c7Smrg 127311bf0794Smrg if (drmmode_crtc->tear_free) 127411bf0794Smrg amdgpu_scanout_flip(pScreen, info, crtc); 127546845023Smrg else if (drmmode_crtc->scanout[drmmode_crtc->scanout_id]) 127611bf0794Smrg amdgpu_scanout_update(crtc); 1277504d986fSmrg } 1278d6c0b56eSmrg } 1279d6c0b56eSmrg 128011bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,0,0,0) 1281d6c0b56eSmrg if (info->use_glamor) 1282d6c0b56eSmrg amdgpu_glamor_flush(pScrn); 128311bf0794Smrg#endif 1284d6c0b56eSmrg 1285504d986fSmrg amdgpu_dirty_update(pScrn); 1286d6c0b56eSmrg} 1287d6c0b56eSmrg 1288d6c0b56eSmrg/* This is called by AMDGPUPreInit to set up the default visual */ 1289d6c0b56eSmrgstatic Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn) 1290d6c0b56eSmrg{ 1291d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1292d6c0b56eSmrg 1293d6c0b56eSmrg if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) 1294d6c0b56eSmrg return FALSE; 1295d6c0b56eSmrg 1296d6c0b56eSmrg switch (pScrn->depth) { 1297d6c0b56eSmrg case 8: 1298d6c0b56eSmrg case 15: 1299d6c0b56eSmrg case 16: 1300d6c0b56eSmrg case 24: 130124b90cf4Smrg case 30: 1302d6c0b56eSmrg break; 1303d6c0b56eSmrg 1304d6c0b56eSmrg default: 1305d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1306d6c0b56eSmrg "Given depth (%d) is not supported by %s driver\n", 1307d6c0b56eSmrg pScrn->depth, AMDGPU_DRIVER_NAME); 1308d6c0b56eSmrg return FALSE; 1309d6c0b56eSmrg } 1310d6c0b56eSmrg 1311d6c0b56eSmrg xf86PrintDepthBpp(pScrn); 1312d6c0b56eSmrg 1313d6c0b56eSmrg info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth); 1314d6c0b56eSmrg info->pixel_bytes = pScrn->bitsPerPixel / 8; 1315d6c0b56eSmrg 1316d6c0b56eSmrg if (info->pix24bpp == 24) { 1317d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1318d6c0b56eSmrg "Amdgpu does NOT support 24bpp\n"); 1319d6c0b56eSmrg return FALSE; 1320d6c0b56eSmrg } 1321d6c0b56eSmrg 1322d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1323d6c0b56eSmrg "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n", 1324d6c0b56eSmrg pScrn->depth, 1325d6c0b56eSmrg info->pixel_bytes, 1326d6c0b56eSmrg info->pixel_bytes > 1 ? "s" : "", info->pix24bpp); 1327d6c0b56eSmrg 1328d6c0b56eSmrg if (!xf86SetDefaultVisual(pScrn, -1)) 1329d6c0b56eSmrg return FALSE; 1330d6c0b56eSmrg 1331d6c0b56eSmrg if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { 1332d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1333d6c0b56eSmrg "Default visual (%s) is not supported at depth %d\n", 1334d6c0b56eSmrg xf86GetVisualName(pScrn->defaultVisual), 1335d6c0b56eSmrg pScrn->depth); 1336d6c0b56eSmrg return FALSE; 1337d6c0b56eSmrg } 1338d6c0b56eSmrg return TRUE; 1339d6c0b56eSmrg} 1340d6c0b56eSmrg 1341d6c0b56eSmrg/* This is called by AMDGPUPreInit to handle all color weight issues */ 1342d6c0b56eSmrgstatic Bool AMDGPUPreInitWeight(ScrnInfoPtr pScrn) 1343d6c0b56eSmrg{ 1344d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1345d6c0b56eSmrg 1346d6c0b56eSmrg /* Save flag for 6 bit DAC to use for 1347d6c0b56eSmrg setting CRTC registers. Otherwise use 1348d6c0b56eSmrg an 8 bit DAC, even if xf86SetWeight sets 1349d6c0b56eSmrg pScrn->rgbBits to some value other than 1350d6c0b56eSmrg 8. */ 1351d6c0b56eSmrg info->dac6bits = FALSE; 1352d6c0b56eSmrg 1353d6c0b56eSmrg if (pScrn->depth > 8) { 1354d6c0b56eSmrg rgb defaultWeight = { 0, 0, 0 }; 1355d6c0b56eSmrg 1356d6c0b56eSmrg if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) 1357d6c0b56eSmrg return FALSE; 1358d6c0b56eSmrg } else { 1359d6c0b56eSmrg pScrn->rgbBits = 8; 1360d6c0b56eSmrg } 1361d6c0b56eSmrg 1362d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1363d6c0b56eSmrg "Using %d bits per RGB (%d bit DAC)\n", 1364d6c0b56eSmrg pScrn->rgbBits, info->dac6bits ? 6 : 8); 1365d6c0b56eSmrg 1366d6c0b56eSmrg return TRUE; 1367d6c0b56eSmrg} 1368d6c0b56eSmrg 1369d6c0b56eSmrgstatic Bool AMDGPUPreInitAccel_KMS(ScrnInfoPtr pScrn) 1370d6c0b56eSmrg{ 1371d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1372d6c0b56eSmrg 1373d6c0b56eSmrg if (xf86ReturnOptValBool(info->Options, OPTION_ACCEL, TRUE)) { 1374d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1375d6c0b56eSmrg Bool use_glamor = TRUE; 1376d6c0b56eSmrg#ifdef HAVE_GBM_BO_USE_LINEAR 1377d6c0b56eSmrg const char *accel_method; 1378d6c0b56eSmrg 1379d6c0b56eSmrg accel_method = xf86GetOptValString(info->Options, OPTION_ACCEL_METHOD); 1380d6c0b56eSmrg if ((accel_method && !strcmp(accel_method, "none"))) 1381d6c0b56eSmrg use_glamor = FALSE; 1382d6c0b56eSmrg#endif 1383d6c0b56eSmrg 1384d6c0b56eSmrg#ifdef DRI2 1385d6c0b56eSmrg info->dri2.available = ! !xf86LoadSubModule(pScrn, "dri2"); 1386d6c0b56eSmrg#endif 1387d6c0b56eSmrg 1388d6c0b56eSmrg if (info->dri2.available) 1389d6c0b56eSmrg info->gbm = gbm_create_device(pAMDGPUEnt->fd); 1390d6c0b56eSmrg 139124b90cf4Smrg if (info->gbm) { 139235d5b7c7Smrg if (use_glamor) { 139335d5b7c7Smrg if (amdgpu_glamor_pre_init(pScrn)) 139435d5b7c7Smrg return TRUE; 139535d5b7c7Smrg 139635d5b7c7Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 139735d5b7c7Smrg "amdgpu_glamor_pre_init returned " 139835d5b7c7Smrg "FALSE, using ShadowFB\n"); 139935d5b7c7Smrg } 140024b90cf4Smrg } else { 140124b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 140224b90cf4Smrg "gbm_create_device returned NULL, using " 140324b90cf4Smrg "ShadowFB\n"); 140424b90cf4Smrg } 140524b90cf4Smrg } else { 140624b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 140724b90cf4Smrg "GPU acceleration disabled, using ShadowFB\n"); 1408d6c0b56eSmrg } 1409d6c0b56eSmrg 1410d6c0b56eSmrg if (!xf86LoadSubModule(pScrn, "shadow")) 141124b90cf4Smrg return FALSE; 1412d6c0b56eSmrg 141324b90cf4Smrg info->dri2.available = FALSE; 141424b90cf4Smrg info->shadow_fb = TRUE; 1415d6c0b56eSmrg return TRUE; 1416d6c0b56eSmrg} 1417d6c0b56eSmrg 141811bf0794Smrgstatic Bool AMDGPUPreInitChipType_KMS(ScrnInfoPtr pScrn, 141911bf0794Smrg struct amdgpu_gpu_info *gpu_info) 1420d6c0b56eSmrg{ 1421d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 142211bf0794Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1423d6c0b56eSmrg 142490f2b693Smrg pScrn->chipset = (char*)amdgpu_get_marketing_name(pAMDGPUEnt->pDev); 142511bf0794Smrg if (!pScrn->chipset) 142611bf0794Smrg pScrn->chipset = "Unknown AMD Radeon GPU"; 1427d6c0b56eSmrg 1428d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 1429d6c0b56eSmrg "Chipset: \"%s\" (ChipID = 0x%04x)\n", 143046845023Smrg pScrn->chipset, gpu_info->asic_id); 1431d6c0b56eSmrg 143211bf0794Smrg info->family = gpu_info->family_id; 1433d6c0b56eSmrg 1434d6c0b56eSmrg return TRUE; 1435d6c0b56eSmrg} 1436d6c0b56eSmrg 143711bf0794Smrgstatic Bool amdgpu_get_tile_config(AMDGPUInfoPtr info, 143811bf0794Smrg struct amdgpu_gpu_info *gpu_info) 1439d6c0b56eSmrg{ 144011bf0794Smrg switch ((gpu_info->gb_addr_cfg & 0x70) >> 4) { 1441d6c0b56eSmrg case 0: 1442d6c0b56eSmrg info->group_bytes = 256; 1443d6c0b56eSmrg break; 1444d6c0b56eSmrg case 1: 1445d6c0b56eSmrg info->group_bytes = 512; 1446d6c0b56eSmrg break; 1447d6c0b56eSmrg default: 1448d6c0b56eSmrg return FALSE; 1449d6c0b56eSmrg } 1450d6c0b56eSmrg 1451d6c0b56eSmrg info->have_tiling_info = TRUE; 1452d6c0b56eSmrg return TRUE; 1453d6c0b56eSmrg} 1454d6c0b56eSmrg 1455d6c0b56eSmrgstatic void AMDGPUSetupCapabilities(ScrnInfoPtr pScrn) 1456d6c0b56eSmrg{ 1457d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1458d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1459d6c0b56eSmrg uint64_t value; 1460d6c0b56eSmrg int ret; 1461d6c0b56eSmrg 1462d6c0b56eSmrg pScrn->capabilities = 0; 1463d6c0b56eSmrg 1464d6c0b56eSmrg /* PRIME offloading requires acceleration */ 1465d6c0b56eSmrg if (!info->use_glamor) 1466d6c0b56eSmrg return; 1467d6c0b56eSmrg 1468d6c0b56eSmrg ret = drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PRIME, &value); 1469d6c0b56eSmrg if (ret == 0) { 1470d6c0b56eSmrg if (value & DRM_PRIME_CAP_EXPORT) 1471504d986fSmrg pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload; 1472504d986fSmrg if (value & DRM_PRIME_CAP_IMPORT) { 1473504d986fSmrg pScrn->capabilities |= RR_Capability_SinkOffload; 1474504d986fSmrg if (info->drmmode.count_crtcs) 1475504d986fSmrg pScrn->capabilities |= RR_Capability_SinkOutput; 1476504d986fSmrg } 1477d6c0b56eSmrg } 1478d6c0b56eSmrg} 1479d6c0b56eSmrg 1480d6c0b56eSmrg/* When the root window is created, initialize the screen contents from 1481d6c0b56eSmrg * console if -background none was specified on the command line 1482d6c0b56eSmrg */ 1483d6c0b56eSmrgstatic Bool AMDGPUCreateWindow_oneshot(WindowPtr pWin) 1484d6c0b56eSmrg{ 1485d6c0b56eSmrg ScreenPtr pScreen = pWin->drawable.pScreen; 1486d6c0b56eSmrg ScrnInfoPtr pScrn; 1487d6c0b56eSmrg AMDGPUInfoPtr info; 1488d6c0b56eSmrg Bool ret; 1489d6c0b56eSmrg 1490d6c0b56eSmrg if (pWin != pScreen->root) 1491d6c0b56eSmrg ErrorF("%s called for non-root window %p\n", __func__, pWin); 1492d6c0b56eSmrg 1493d6c0b56eSmrg pScrn = xf86ScreenToScrn(pScreen); 1494d6c0b56eSmrg info = AMDGPUPTR(pScrn); 1495d6c0b56eSmrg pScreen->CreateWindow = info->CreateWindow; 1496d6c0b56eSmrg ret = pScreen->CreateWindow(pWin); 1497d6c0b56eSmrg 1498d6c0b56eSmrg if (ret) 1499d6c0b56eSmrg drmmode_copy_fb(pScrn, &info->drmmode); 1500d6c0b56eSmrg 1501d6c0b56eSmrg return ret; 1502d6c0b56eSmrg} 1503d6c0b56eSmrg 1504e49c54bcSmrgstatic void amdgpu_determine_cursor_size(int fd, AMDGPUInfoPtr info) 1505e49c54bcSmrg{ 1506e49c54bcSmrg uint64_t value; 1507e49c54bcSmrg 1508e49c54bcSmrg if (drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &value) == 0) 1509e49c54bcSmrg info->cursor_w = value; 1510e49c54bcSmrg else if (info->family < AMDGPU_FAMILY_CI) 1511e49c54bcSmrg info->cursor_w = CURSOR_WIDTH; 1512e49c54bcSmrg else 1513e49c54bcSmrg info->cursor_w = CURSOR_WIDTH_CIK; 1514e49c54bcSmrg 1515e49c54bcSmrg if (drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &value) == 0) 1516e49c54bcSmrg info->cursor_h = value; 1517e49c54bcSmrg else if (info->family < AMDGPU_FAMILY_CI) 1518e49c54bcSmrg info->cursor_h = CURSOR_HEIGHT; 1519e49c54bcSmrg else 1520e49c54bcSmrg info->cursor_h = CURSOR_HEIGHT_CIK; 1521e49c54bcSmrg} 1522e49c54bcSmrg 152311bf0794Smrg/* When the root window is mapped, set the initial modes */ 152424b90cf4Smrgvoid AMDGPUWindowExposures_oneshot(WindowPtr pWin, RegionPtr pRegion 152511bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 152624b90cf4Smrg , RegionPtr pBSRegion 152711bf0794Smrg#endif 152824b90cf4Smrg ) 152911bf0794Smrg{ 153011bf0794Smrg ScreenPtr pScreen = pWin->drawable.pScreen; 153111bf0794Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 153211bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 153311bf0794Smrg 153411bf0794Smrg if (pWin != pScreen->root) 153511bf0794Smrg ErrorF("%s called for non-root window %p\n", __func__, pWin); 153611bf0794Smrg 153711bf0794Smrg pScreen->WindowExposures = info->WindowExposures; 153811bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 153911bf0794Smrg pScreen->WindowExposures(pWin, pRegion, pBSRegion); 154011bf0794Smrg#else 154111bf0794Smrg pScreen->WindowExposures(pWin, pRegion); 154211bf0794Smrg#endif 154311bf0794Smrg 154411bf0794Smrg amdgpu_glamor_finish(pScrn); 154511bf0794Smrg drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE); 154611bf0794Smrg} 154711bf0794Smrg 1548d6c0b56eSmrgBool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags) 1549d6c0b56eSmrg{ 1550d6c0b56eSmrg AMDGPUInfoPtr info; 1551d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt; 155211bf0794Smrg struct amdgpu_gpu_info gpu_info; 155311bf0794Smrg MessageType from; 1554d6c0b56eSmrg Gamma zeros = { 0.0, 0.0, 0.0 }; 1555d6c0b56eSmrg int cpp; 1556d6c0b56eSmrg uint64_t heap_size = 0; 1557d6c0b56eSmrg uint64_t max_allocation = 0; 1558d6c0b56eSmrg 1559d6c0b56eSmrg if (flags & PROBE_DETECT) 1560d6c0b56eSmrg return TRUE; 1561d6c0b56eSmrg 1562d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1563d6c0b56eSmrg "AMDGPUPreInit_KMS\n"); 1564d6c0b56eSmrg if (pScrn->numEntities != 1) 1565d6c0b56eSmrg return FALSE; 156690f2b693Smrg 156790f2b693Smrg pAMDGPUEnt = xf86GetEntityPrivate(pScrn->entityList[0], 156890f2b693Smrg getAMDGPUEntityIndex())->ptr; 156990f2b693Smrg 1570d6c0b56eSmrg if (!AMDGPUGetRec(pScrn)) 1571d6c0b56eSmrg return FALSE; 1572d6c0b56eSmrg 1573d6c0b56eSmrg info = AMDGPUPTR(pScrn); 157490f2b693Smrg info->instance_id = pAMDGPUEnt->num_scrns++; 157590f2b693Smrg pAMDGPUEnt->scrn[info->instance_id] = pScrn; 157690f2b693Smrg 1577d6c0b56eSmrg info->pEnt = 1578d6c0b56eSmrg xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); 1579d6c0b56eSmrg if (info->pEnt->location.type != BUS_PCI 1580d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS 1581d6c0b56eSmrg && info->pEnt->location.type != BUS_PLATFORM 1582d6c0b56eSmrg#endif 1583d6c0b56eSmrg ) 158424b90cf4Smrg return FALSE; 1585d6c0b56eSmrg 158690f2b693Smrg if (xf86IsEntityShared(pScrn->entityList[0]) && 158790f2b693Smrg info->instance_id == 0) { 158890f2b693Smrg xf86SetPrimInitDone(pScrn->entityList[0]); 1589d6c0b56eSmrg } 1590d6c0b56eSmrg 1591d6c0b56eSmrg pScrn->monitor = pScrn->confScreen->monitor; 1592d6c0b56eSmrg 1593d6c0b56eSmrg if (!AMDGPUPreInitVisual(pScrn)) 159424b90cf4Smrg return FALSE; 1595d6c0b56eSmrg 1596d6c0b56eSmrg xf86CollectOptions(pScrn, NULL); 1597d6c0b56eSmrg if (!(info->Options = malloc(sizeof(AMDGPUOptions_KMS)))) 159824b90cf4Smrg return FALSE; 1599d6c0b56eSmrg 1600d6c0b56eSmrg memcpy(info->Options, AMDGPUOptions_KMS, sizeof(AMDGPUOptions_KMS)); 1601d6c0b56eSmrg xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options); 1602d6c0b56eSmrg 1603d6c0b56eSmrg if (!AMDGPUPreInitWeight(pScrn)) 160424b90cf4Smrg return FALSE; 1605d6c0b56eSmrg 160611bf0794Smrg memset(&gpu_info, 0, sizeof(gpu_info)); 160711bf0794Smrg amdgpu_query_gpu_info(pAMDGPUEnt->pDev, &gpu_info); 160811bf0794Smrg 160911bf0794Smrg if (!AMDGPUPreInitChipType_KMS(pScrn, &gpu_info)) 161024b90cf4Smrg return FALSE; 1611d6c0b56eSmrg 1612d6c0b56eSmrg info->dri2.available = FALSE; 1613d6c0b56eSmrg info->dri2.enabled = FALSE; 161490f2b693Smrg info->dri2.pKernelDRMVersion = drmGetVersion(pAMDGPUEnt->fd); 161590f2b693Smrg if (info->dri2.pKernelDRMVersion == NULL) { 161690f2b693Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 161790f2b693Smrg "AMDGPUDRIGetVersion failed to get the DRM version\n"); 161890f2b693Smrg return FALSE; 161990f2b693Smrg } 1620d6c0b56eSmrg 1621d6c0b56eSmrg /* Get ScreenInit function */ 1622d6c0b56eSmrg if (!xf86LoadSubModule(pScrn, "fb")) 1623d6c0b56eSmrg return FALSE; 1624d6c0b56eSmrg 1625d6c0b56eSmrg if (!AMDGPUPreInitAccel_KMS(pScrn)) 162624b90cf4Smrg return FALSE; 1627d6c0b56eSmrg 162835d5b7c7Smrg amdgpu_drm_queue_init(pScrn); 1629d6c0b56eSmrg 1630d6c0b56eSmrg /* don't enable tiling if accel is not enabled */ 1631d6c0b56eSmrg if (info->use_glamor) { 1632d6c0b56eSmrg /* set default group bytes, overridden by kernel info below */ 1633d6c0b56eSmrg info->group_bytes = 256; 1634d6c0b56eSmrg info->have_tiling_info = FALSE; 163511bf0794Smrg amdgpu_get_tile_config(info, &gpu_info); 1636d6c0b56eSmrg } 1637d6c0b56eSmrg 1638d6c0b56eSmrg if (info->use_glamor) { 163911bf0794Smrg from = X_DEFAULT; 1640d6c0b56eSmrg 164111bf0794Smrg info->tear_free = 2; 164211bf0794Smrg if (xf86GetOptValBool(info->Options, OPTION_TEAR_FREE, 164311bf0794Smrg &info->tear_free)) 164411bf0794Smrg from = X_CONFIG; 164511bf0794Smrg xf86DrvMsg(pScrn->scrnIndex, from, "TearFree property default: %s\n", 164611bf0794Smrg info->tear_free == 2 ? "auto" : (info->tear_free ? "on" : "off")); 1647d6c0b56eSmrg 1648d6c0b56eSmrg info->shadow_primary = 1649d6c0b56eSmrg xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE); 1650d6c0b56eSmrg 1651d6c0b56eSmrg if (info->shadow_primary) 1652d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n"); 165390f2b693Smrg 165490f2b693Smrg if (!pScrn->is_gpu) { 165590f2b693Smrg from = xf86GetOptValBool(info->Options, OPTION_VARIABLE_REFRESH, 165690f2b693Smrg &info->vrr_support) ? X_CONFIG : X_DEFAULT; 165790f2b693Smrg 165890f2b693Smrg xf86DrvMsg(pScrn->scrnIndex, from, "VariableRefresh: %sabled\n", 165990f2b693Smrg info->vrr_support ? "en" : "dis"); 1660e49c54bcSmrg 1661e49c54bcSmrg info->async_flip_secondaries = FALSE; 1662e49c54bcSmrg from = xf86GetOptValBool(info->Options, OPTION_ASYNC_FLIP_SECONDARIES, 1663e49c54bcSmrg &info->async_flip_secondaries) ? X_CONFIG : X_DEFAULT; 1664e49c54bcSmrg 1665e49c54bcSmrg xf86DrvMsg(pScrn->scrnIndex, from, "AsyncFlipSecondaries: %sabled\n", 1666e49c54bcSmrg info->async_flip_secondaries ? "en" : "dis"); 166790f2b693Smrg } 1668d6c0b56eSmrg } 1669d6c0b56eSmrg 167024b90cf4Smrg if (!pScrn->is_gpu) { 167111bf0794Smrg info->allowPageFlip = xf86ReturnOptValBool(info->Options, 167211bf0794Smrg OPTION_PAGE_FLIP, 167311bf0794Smrg TRUE); 167477d6d1ecSmrg if (info->shadow_primary) { 167511bf0794Smrg xf86DrvMsg(pScrn->scrnIndex, 167611bf0794Smrg info->allowPageFlip ? X_WARNING : X_DEFAULT, 167711bf0794Smrg "KMS Pageflipping: disabled%s\n", 167811bf0794Smrg info->allowPageFlip ? 167977d6d1ecSmrg " because of ShadowPrimary" : ""); 168011bf0794Smrg info->allowPageFlip = FALSE; 168111bf0794Smrg } else { 168211bf0794Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 168311bf0794Smrg "KMS Pageflipping: %sabled\n", 168411bf0794Smrg info->allowPageFlip ? "en" : "dis"); 168511bf0794Smrg } 1686d6c0b56eSmrg } 1687d6c0b56eSmrg 1688d6c0b56eSmrg if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) { 1689d6c0b56eSmrg info->drmmode.delete_dp_12_displays = TRUE; 1690d6c0b56eSmrg } 1691d6c0b56eSmrg 1692d6c0b56eSmrg if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == 1693d6c0b56eSmrg FALSE) { 1694d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1695d6c0b56eSmrg "Kernel modesetting setup failed\n"); 169624b90cf4Smrg return FALSE; 1697d6c0b56eSmrg } 1698d6c0b56eSmrg 1699504d986fSmrg AMDGPUSetupCapabilities(pScrn); 1700504d986fSmrg 1701d6c0b56eSmrg if (info->drmmode.count_crtcs == 1) 1702d6c0b56eSmrg pAMDGPUEnt->HasCRTC2 = FALSE; 1703d6c0b56eSmrg else 1704d6c0b56eSmrg pAMDGPUEnt->HasCRTC2 = TRUE; 1705d6c0b56eSmrg 1706e49c54bcSmrg amdgpu_determine_cursor_size(pAMDGPUEnt->fd, info); 1707d6c0b56eSmrg 1708d6c0b56eSmrg amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_GTT, 1709d6c0b56eSmrg &heap_size, &max_allocation); 1710d6c0b56eSmrg info->gart_size = heap_size; 1711d6c0b56eSmrg amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_VRAM, 1712d6c0b56eSmrg &heap_size, &max_allocation); 1713d6c0b56eSmrg info->vram_size = max_allocation; 1714d6c0b56eSmrg 1715d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1716d6c0b56eSmrg "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n", 1717d6c0b56eSmrg (unsigned long long)info->gart_size, 1718d6c0b56eSmrg (unsigned long long)heap_size, 1719d6c0b56eSmrg (unsigned long long)max_allocation); 1720d6c0b56eSmrg 1721d6c0b56eSmrg cpp = pScrn->bitsPerPixel / 8; 1722d6c0b56eSmrg pScrn->displayWidth = 1723d6c0b56eSmrg AMDGPU_ALIGN(pScrn->virtualX, drmmode_get_pitch_align(pScrn, cpp)); 1724d6c0b56eSmrg 1725d6c0b56eSmrg /* Set display resolution */ 1726d6c0b56eSmrg xf86SetDpi(pScrn, 0, 0); 1727d6c0b56eSmrg 1728d6c0b56eSmrg if (!xf86SetGamma(pScrn, zeros)) 1729d6c0b56eSmrg return FALSE; 1730d6c0b56eSmrg 1731d6c0b56eSmrg if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { 1732d6c0b56eSmrg if (!xf86LoadSubModule(pScrn, "ramdac")) 1733d6c0b56eSmrg return FALSE; 1734d6c0b56eSmrg } 1735d6c0b56eSmrg 173635d5b7c7Smrg if (!pScrn->modes 1737d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS 1738d6c0b56eSmrg && !pScrn->is_gpu 1739d6c0b56eSmrg#endif 1740d6c0b56eSmrg ) { 1741d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); 174224b90cf4Smrg return FALSE; 1743d6c0b56eSmrg } 1744d6c0b56eSmrg 1745d6c0b56eSmrg return TRUE; 1746d6c0b56eSmrg} 1747d6c0b56eSmrg 1748d6c0b56eSmrgstatic Bool AMDGPUCursorInit_KMS(ScreenPtr pScreen) 1749d6c0b56eSmrg{ 1750d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1751d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1752d6c0b56eSmrg 175324b90cf4Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 175424b90cf4Smrg "Initializing Cursor\n"); 175524b90cf4Smrg 175624b90cf4Smrg /* Set Silken Mouse */ 175724b90cf4Smrg xf86SetSilkenMouse(pScreen); 175824b90cf4Smrg 175924b90cf4Smrg /* Cursor setup */ 176024b90cf4Smrg miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 176124b90cf4Smrg 176224b90cf4Smrg if (info->allowPageFlip) { 176324b90cf4Smrg miPointerScreenPtr PointPriv = 176424b90cf4Smrg dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); 176524b90cf4Smrg 176624b90cf4Smrg if (!dixRegisterScreenPrivateKey(&amdgpu_device_private_key, pScreen, 176724b90cf4Smrg PRIVATE_DEVICE, 176824b90cf4Smrg sizeof(struct amdgpu_device_priv))) { 176924b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "dixRegisterScreenPrivateKey failed\n"); 177024b90cf4Smrg return FALSE; 177124b90cf4Smrg } 177224b90cf4Smrg 177335d5b7c7Smrg info->SpriteFuncs = PointPriv->spriteFuncs; 177435d5b7c7Smrg PointPriv->spriteFuncs = &drmmode_sprite_funcs; 177524b90cf4Smrg } 177624b90cf4Smrg 177724b90cf4Smrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 177824b90cf4Smrg return TRUE; 177924b90cf4Smrg 178024b90cf4Smrg if (!xf86_cursors_init(pScreen, info->cursor_w, info->cursor_h, 178124b90cf4Smrg HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 178224b90cf4Smrg HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | 178324b90cf4Smrg HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | 178424b90cf4Smrg HARDWARE_CURSOR_UPDATE_UNHIDDEN | 178524b90cf4Smrg HARDWARE_CURSOR_ARGB)) { 178624b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86_cursors_init failed\n"); 178724b90cf4Smrg return FALSE; 178824b90cf4Smrg } 178924b90cf4Smrg 179024b90cf4Smrg return TRUE; 1791d6c0b56eSmrg} 1792d6c0b56eSmrg 1793d6c0b56eSmrgvoid AMDGPUBlank(ScrnInfoPtr pScrn) 1794d6c0b56eSmrg{ 1795d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1796d6c0b56eSmrg xf86OutputPtr output; 1797d6c0b56eSmrg xf86CrtcPtr crtc; 1798d6c0b56eSmrg int o, c; 1799d6c0b56eSmrg 1800d6c0b56eSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 1801d6c0b56eSmrg crtc = xf86_config->crtc[c]; 1802d6c0b56eSmrg for (o = 0; o < xf86_config->num_output; o++) { 1803d6c0b56eSmrg output = xf86_config->output[o]; 1804d6c0b56eSmrg if (output->crtc != crtc) 1805d6c0b56eSmrg continue; 1806d6c0b56eSmrg 1807d6c0b56eSmrg output->funcs->dpms(output, DPMSModeOff); 1808d6c0b56eSmrg } 1809d6c0b56eSmrg crtc->funcs->dpms(crtc, DPMSModeOff); 1810d6c0b56eSmrg } 1811d6c0b56eSmrg} 1812d6c0b56eSmrg 1813d6c0b56eSmrgvoid AMDGPUUnblank(ScrnInfoPtr pScrn) 1814d6c0b56eSmrg{ 1815d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1816d6c0b56eSmrg xf86OutputPtr output; 1817d6c0b56eSmrg xf86CrtcPtr crtc; 1818d6c0b56eSmrg int o, c; 1819d6c0b56eSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 1820d6c0b56eSmrg crtc = xf86_config->crtc[c]; 1821d6c0b56eSmrg if (!crtc->enabled) 1822d6c0b56eSmrg continue; 1823d6c0b56eSmrg crtc->funcs->dpms(crtc, DPMSModeOn); 1824d6c0b56eSmrg for (o = 0; o < xf86_config->num_output; o++) { 1825d6c0b56eSmrg output = xf86_config->output[o]; 1826d6c0b56eSmrg if (output->crtc != crtc) 1827d6c0b56eSmrg continue; 1828d6c0b56eSmrg output->funcs->dpms(output, DPMSModeOn); 1829d6c0b56eSmrg } 1830d6c0b56eSmrg } 1831d6c0b56eSmrg} 1832d6c0b56eSmrg 1833d6c0b56eSmrgstatic Bool amdgpu_set_drm_master(ScrnInfoPtr pScrn) 1834d6c0b56eSmrg{ 1835d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1836d6c0b56eSmrg int err; 1837d6c0b56eSmrg 1838d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD 1839d6c0b56eSmrg if (pAMDGPUEnt->platform_dev && 1840d6c0b56eSmrg (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD)) 1841d6c0b56eSmrg return TRUE; 1842d6c0b56eSmrg#endif 1843d6c0b56eSmrg 1844d6c0b56eSmrg err = drmSetMaster(pAMDGPUEnt->fd); 1845d6c0b56eSmrg if (err) 1846d6c0b56eSmrg ErrorF("Unable to retrieve master\n"); 1847d6c0b56eSmrg 1848d6c0b56eSmrg return err == 0; 1849d6c0b56eSmrg} 1850d6c0b56eSmrg 1851d6c0b56eSmrgstatic void amdgpu_drop_drm_master(ScrnInfoPtr pScrn) 1852d6c0b56eSmrg{ 1853d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1854d6c0b56eSmrg 1855d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD 1856d6c0b56eSmrg if (pAMDGPUEnt->platform_dev && 1857d6c0b56eSmrg (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD)) 1858d6c0b56eSmrg return; 1859d6c0b56eSmrg#endif 1860d6c0b56eSmrg 1861d6c0b56eSmrg drmDropMaster(pAMDGPUEnt->fd); 1862d6c0b56eSmrg} 1863d6c0b56eSmrg 1864d6c0b56eSmrg 186524b90cf4Smrgstatic 186624b90cf4SmrgCARD32 cleanup_black_fb(OsTimerPtr timer, CARD32 now, pointer data) 186724b90cf4Smrg{ 186824b90cf4Smrg ScreenPtr screen = data; 186924b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 187024b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 187124b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 187224b90cf4Smrg int c; 187324b90cf4Smrg 187446845023Smrg if (xf86ScreenToScrn(amdgpu_primary_screen(screen))->vtSema) 187524b90cf4Smrg return 0; 187624b90cf4Smrg 187724b90cf4Smrg /* Unreference the all-black FB created by AMDGPULeaveVT_KMS. After 187824b90cf4Smrg * this, there should be no FB left created by this driver. 187924b90cf4Smrg */ 188024b90cf4Smrg for (c = 0; c < xf86_config->num_crtc; c++) { 188124b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = 188224b90cf4Smrg xf86_config->crtc[c]->driver_private; 188324b90cf4Smrg 188424b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 188524b90cf4Smrg } 188624b90cf4Smrg 188724b90cf4Smrg TimerFree(timer); 188824b90cf4Smrg return 0; 188924b90cf4Smrg} 1890d6c0b56eSmrg 1891d6c0b56eSmrgstatic Bool AMDGPUSaveScreen_KMS(ScreenPtr pScreen, int mode) 1892d6c0b56eSmrg{ 1893d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1894d6c0b56eSmrg Bool unblank; 1895d6c0b56eSmrg 1896d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1897d6c0b56eSmrg "AMDGPUSaveScreen(%d)\n", mode); 1898d6c0b56eSmrg 1899d6c0b56eSmrg unblank = xf86IsUnblank(mode); 1900d6c0b56eSmrg if (unblank) 1901d6c0b56eSmrg SetTimeSinceLastInputEvent(); 1902d6c0b56eSmrg 1903d6c0b56eSmrg if ((pScrn != NULL) && pScrn->vtSema) { 1904d6c0b56eSmrg if (unblank) 1905d6c0b56eSmrg AMDGPUUnblank(pScrn); 1906d6c0b56eSmrg else 1907d6c0b56eSmrg AMDGPUBlank(pScrn); 1908d6c0b56eSmrg } 1909d6c0b56eSmrg return TRUE; 1910d6c0b56eSmrg} 1911d6c0b56eSmrg 1912d6c0b56eSmrg/* Called at the end of each server generation. Restore the original 1913d6c0b56eSmrg * text mode, unmap video memory, and unwrap and call the saved 1914d6c0b56eSmrg * CloseScreen function. 1915d6c0b56eSmrg */ 191624b90cf4Smrgstatic Bool AMDGPUCloseScreen_KMS(ScreenPtr pScreen) 1917d6c0b56eSmrg{ 1918d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1919d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1920d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1921d6c0b56eSmrg 1922d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1923d6c0b56eSmrg "AMDGPUCloseScreen\n"); 1924d6c0b56eSmrg 1925d6c0b56eSmrg /* Clear mask of assigned crtc's in this generation */ 1926d6c0b56eSmrg pAMDGPUEnt->assigned_crtcs = 0; 1927d6c0b56eSmrg 1928d6c0b56eSmrg drmmode_uevent_fini(pScrn, &info->drmmode); 1929d6c0b56eSmrg amdgpu_drm_queue_close(pScrn); 1930d6c0b56eSmrg 1931504d986fSmrg if (info->callback_event_type != -1) { 1932504d986fSmrg DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn); 1933504d986fSmrg DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn); 1934504d986fSmrg } 1935d6c0b56eSmrg 1936d6c0b56eSmrg amdgpu_sync_close(pScreen); 1937d6c0b56eSmrg amdgpu_drop_drm_master(pScrn); 1938d6c0b56eSmrg 1939d6c0b56eSmrg drmmode_fini(pScrn, &info->drmmode); 1940d6c0b56eSmrg if (info->dri2.enabled) { 1941d6c0b56eSmrg amdgpu_dri2_close_screen(pScreen); 1942d6c0b56eSmrg } 1943d6c0b56eSmrg amdgpu_glamor_fini(pScreen); 1944d6c0b56eSmrg pScrn->vtSema = FALSE; 1945d6c0b56eSmrg xf86ClearPrimInitDone(info->pEnt->index); 194624b90cf4Smrg 194724b90cf4Smrg if (info->allowPageFlip) { 194824b90cf4Smrg miPointerScreenPtr PointPriv = 194924b90cf4Smrg dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); 195024b90cf4Smrg 195135d5b7c7Smrg if (PointPriv->spriteFuncs == &drmmode_sprite_funcs) 195235d5b7c7Smrg PointPriv->spriteFuncs = info->SpriteFuncs; 195324b90cf4Smrg } 195424b90cf4Smrg 1955d6c0b56eSmrg pScreen->BlockHandler = info->BlockHandler; 1956d6c0b56eSmrg pScreen->CloseScreen = info->CloseScreen; 195724b90cf4Smrg return pScreen->CloseScreen(pScreen); 1958d6c0b56eSmrg} 1959d6c0b56eSmrg 196024b90cf4Smrgvoid AMDGPUFreeScreen_KMS(ScrnInfoPtr pScrn) 1961d6c0b56eSmrg{ 1962d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1963d6c0b56eSmrg "AMDGPUFreeScreen\n"); 1964d6c0b56eSmrg 1965d6c0b56eSmrg AMDGPUFreeRec(pScrn); 1966d6c0b56eSmrg} 1967d6c0b56eSmrg 196824b90cf4SmrgBool AMDGPUScreenInit_KMS(ScreenPtr pScreen, int argc, char **argv) 1969d6c0b56eSmrg{ 1970d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1971d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1972d6c0b56eSmrg int subPixelOrder = SubPixelUnknown; 1973d6c0b56eSmrg MessageType from; 1974d6c0b56eSmrg Bool value; 1975d6c0b56eSmrg int driLevel; 1976d6c0b56eSmrg const char *s; 1977d6c0b56eSmrg void *front_ptr; 1978d6c0b56eSmrg 1979d6c0b56eSmrg pScrn->fbOffset = 0; 1980d6c0b56eSmrg 1981d6c0b56eSmrg miClearVisualTypes(); 1982d6c0b56eSmrg if (!miSetVisualTypes(pScrn->depth, 1983d6c0b56eSmrg miGetDefaultVisualMask(pScrn->depth), 1984d6c0b56eSmrg pScrn->rgbBits, pScrn->defaultVisual)) 1985d6c0b56eSmrg return FALSE; 1986d6c0b56eSmrg miSetPixmapDepths(); 1987d6c0b56eSmrg 1988d6c0b56eSmrg if (!amdgpu_set_drm_master(pScrn)) 1989d6c0b56eSmrg return FALSE; 1990d6c0b56eSmrg 1991d6c0b56eSmrg info->directRenderingEnabled = FALSE; 1992d6c0b56eSmrg if (info->shadow_fb == FALSE) 1993d6c0b56eSmrg info->directRenderingEnabled = amdgpu_dri2_screen_init(pScreen); 1994d6c0b56eSmrg 1995d6c0b56eSmrg if (!amdgpu_setup_kernel_mem(pScreen)) { 1996d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1997d6c0b56eSmrg "amdgpu_setup_kernel_mem failed\n"); 1998d6c0b56eSmrg return FALSE; 1999d6c0b56eSmrg } 2000d6c0b56eSmrg front_ptr = info->front_buffer->cpu_ptr; 2001d6c0b56eSmrg 2002d6c0b56eSmrg if (info->shadow_fb) { 2003d6c0b56eSmrg info->fb_shadow = calloc(1, 2004d6c0b56eSmrg pScrn->displayWidth * pScrn->virtualY * 2005d6c0b56eSmrg ((pScrn->bitsPerPixel + 7) >> 3)); 200635d5b7c7Smrg if (!info->fb_shadow) { 2007d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2008d6c0b56eSmrg "Failed to allocate shadow framebuffer\n"); 200924b90cf4Smrg return FALSE; 2010d6c0b56eSmrg } else { 2011d6c0b56eSmrg if (!fbScreenInit(pScreen, info->fb_shadow, 2012d6c0b56eSmrg pScrn->virtualX, pScrn->virtualY, 2013d6c0b56eSmrg pScrn->xDpi, pScrn->yDpi, 2014d6c0b56eSmrg pScrn->displayWidth, 2015d6c0b56eSmrg pScrn->bitsPerPixel)) 2016d6c0b56eSmrg return FALSE; 2017d6c0b56eSmrg } 2018d6c0b56eSmrg } 2019d6c0b56eSmrg 2020d6c0b56eSmrg if (info->shadow_fb == FALSE) { 2021d6c0b56eSmrg /* Init fb layer */ 2022d6c0b56eSmrg if (!fbScreenInit(pScreen, front_ptr, 2023d6c0b56eSmrg pScrn->virtualX, pScrn->virtualY, 2024d6c0b56eSmrg pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, 2025d6c0b56eSmrg pScrn->bitsPerPixel)) 2026d6c0b56eSmrg return FALSE; 2027d6c0b56eSmrg } 2028d6c0b56eSmrg 2029d6c0b56eSmrg xf86SetBlackWhitePixels(pScreen); 2030d6c0b56eSmrg 2031d6c0b56eSmrg if (pScrn->bitsPerPixel > 8) { 2032d6c0b56eSmrg VisualPtr visual; 2033d6c0b56eSmrg 2034d6c0b56eSmrg visual = pScreen->visuals + pScreen->numVisuals; 2035d6c0b56eSmrg while (--visual >= pScreen->visuals) { 2036d6c0b56eSmrg if ((visual->class | DynamicClass) == DirectColor) { 2037d6c0b56eSmrg visual->offsetRed = pScrn->offset.red; 2038d6c0b56eSmrg visual->offsetGreen = pScrn->offset.green; 2039d6c0b56eSmrg visual->offsetBlue = pScrn->offset.blue; 2040d6c0b56eSmrg visual->redMask = pScrn->mask.red; 2041d6c0b56eSmrg visual->greenMask = pScrn->mask.green; 2042d6c0b56eSmrg visual->blueMask = pScrn->mask.blue; 2043d6c0b56eSmrg } 2044d6c0b56eSmrg } 2045d6c0b56eSmrg } 2046d6c0b56eSmrg 2047d6c0b56eSmrg /* Must be after RGB order fixed */ 2048d6c0b56eSmrg fbPictureInit(pScreen, 0, 0); 2049d6c0b56eSmrg 2050d6c0b56eSmrg#ifdef RENDER 2051d6c0b56eSmrg if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) { 2052d6c0b56eSmrg if (strcmp(s, "RGB") == 0) 2053d6c0b56eSmrg subPixelOrder = SubPixelHorizontalRGB; 2054d6c0b56eSmrg else if (strcmp(s, "BGR") == 0) 2055d6c0b56eSmrg subPixelOrder = SubPixelHorizontalBGR; 2056d6c0b56eSmrg else if (strcmp(s, "NONE") == 0) 2057d6c0b56eSmrg subPixelOrder = SubPixelNone; 2058d6c0b56eSmrg PictureSetSubpixelOrder(pScreen, subPixelOrder); 2059d6c0b56eSmrg } 2060d6c0b56eSmrg#endif 2061d6c0b56eSmrg 2062e49c54bcSmrg if (xorgGetVersion() >= XORG_VERSION_NUMERIC(1,18,3,0,0)) 2063e49c54bcSmrg value = info->use_glamor; 2064e49c54bcSmrg else 2065e49c54bcSmrg value = FALSE; 2066e49c54bcSmrg from = X_DEFAULT; 2067d6c0b56eSmrg 2068e49c54bcSmrg if (info->use_glamor) { 2069e49c54bcSmrg if (xf86GetOptValBool(info->Options, OPTION_DRI3, &value)) 2070e49c54bcSmrg from = X_CONFIG; 2071d6c0b56eSmrg 2072e49c54bcSmrg if (xf86GetOptValInteger(info->Options, OPTION_DRI, &driLevel) && 2073e49c54bcSmrg (driLevel == 2 || driLevel == 3)) { 2074e49c54bcSmrg from = X_CONFIG; 2075e49c54bcSmrg value = driLevel == 3; 2076d6c0b56eSmrg } 2077e49c54bcSmrg } 2078d6c0b56eSmrg 2079e49c54bcSmrg if (value) { 2080e49c54bcSmrg value = amdgpu_sync_init(pScreen) && 2081e49c54bcSmrg amdgpu_present_screen_init(pScreen) && 2082e49c54bcSmrg amdgpu_dri3_screen_init(pScreen); 2083d6c0b56eSmrg 2084e49c54bcSmrg if (!value) 2085e49c54bcSmrg from = X_WARNING; 208611bf0794Smrg } 2087d6c0b56eSmrg 2088e49c54bcSmrg xf86DrvMsg(pScrn->scrnIndex, from, "DRI3 %sabled\n", value ? "en" : "dis"); 2089e49c54bcSmrg 2090d6c0b56eSmrg pScrn->vtSema = TRUE; 2091d6c0b56eSmrg xf86SetBackingStore(pScreen); 2092d6c0b56eSmrg 2093d6c0b56eSmrg if (info->directRenderingEnabled) { 2094d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2095d6c0b56eSmrg "Direct rendering enabled\n"); 2096d6c0b56eSmrg } else { 2097d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2098d6c0b56eSmrg "Direct rendering disabled\n"); 2099d6c0b56eSmrg } 2100d6c0b56eSmrg 2101d6c0b56eSmrg if (info->use_glamor && info->directRenderingEnabled) { 2102d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2103d6c0b56eSmrg "Initializing Acceleration\n"); 2104d6c0b56eSmrg if (amdgpu_glamor_init(pScreen)) { 2105d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2106d6c0b56eSmrg "Acceleration enabled\n"); 2107d6c0b56eSmrg } else { 2108d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2109d6c0b56eSmrg "Acceleration initialization failed\n"); 2110d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2111d6c0b56eSmrg "2D and 3D acceleration disabled\n"); 2112d6c0b56eSmrg info->use_glamor = FALSE; 2113d6c0b56eSmrg } 2114d6c0b56eSmrg } else if (info->directRenderingEnabled) { 2115d6c0b56eSmrg if (!amdgpu_pixmap_init(pScreen)) 2116d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D acceleration disabled\n"); 2117d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration disabled\n"); 2118d6c0b56eSmrg } else { 211924b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D acceleration disabled\n"); 2120d6c0b56eSmrg } 2121d6c0b56eSmrg 2122d6c0b56eSmrg /* Init DPMS */ 2123d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2124d6c0b56eSmrg "Initializing DPMS\n"); 2125d6c0b56eSmrg xf86DPMSInit(pScreen, xf86DPMSSet, 0); 2126d6c0b56eSmrg 212724b90cf4Smrg if (!AMDGPUCursorInit_KMS(pScreen)) 212824b90cf4Smrg return FALSE; 2129d6c0b56eSmrg 2130d6c0b56eSmrg /* DGA setup */ 2131d6c0b56eSmrg#ifdef XFreeXDGA 2132d6c0b56eSmrg /* DGA is dangerous on kms as the base and framebuffer location may change: 2133d6c0b56eSmrg * http://lists.freedesktop.org/archives/xorg-devel/2009-September/002113.html 2134d6c0b56eSmrg */ 2135d6c0b56eSmrg /* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */ 2136d6c0b56eSmrg#endif 213724b90cf4Smrg if (info->shadow_fb == FALSE && !pScreen->isGPU) { 2138d6c0b56eSmrg /* Init Xv */ 2139d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2140d6c0b56eSmrg "Initializing Xv\n"); 2141d6c0b56eSmrg AMDGPUInitVideo(pScreen); 2142d6c0b56eSmrg } 2143d6c0b56eSmrg 2144d6c0b56eSmrg if (info->shadow_fb == TRUE) { 2145d6c0b56eSmrg if (!shadowSetup(pScreen)) { 2146d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2147d6c0b56eSmrg "Shadowfb initialization failed\n"); 2148d6c0b56eSmrg return FALSE; 2149d6c0b56eSmrg } 2150d6c0b56eSmrg } 2151d6c0b56eSmrg pScrn->pScreen = pScreen; 2152d6c0b56eSmrg 215324b90cf4Smrg if (!pScreen->isGPU) { 215411bf0794Smrg if (serverGeneration == 1 && bgNoneRoot && info->use_glamor) { 215511bf0794Smrg info->CreateWindow = pScreen->CreateWindow; 215611bf0794Smrg pScreen->CreateWindow = AMDGPUCreateWindow_oneshot; 215711bf0794Smrg } 215811bf0794Smrg info->WindowExposures = pScreen->WindowExposures; 215911bf0794Smrg pScreen->WindowExposures = AMDGPUWindowExposures_oneshot; 2160d6c0b56eSmrg } 2161d6c0b56eSmrg 2162d6c0b56eSmrg /* Provide SaveScreen & wrap BlockHandler and CloseScreen */ 2163d6c0b56eSmrg /* Wrap CloseScreen */ 2164d6c0b56eSmrg info->CloseScreen = pScreen->CloseScreen; 2165d6c0b56eSmrg pScreen->CloseScreen = AMDGPUCloseScreen_KMS; 2166d6c0b56eSmrg pScreen->SaveScreen = AMDGPUSaveScreen_KMS; 2167d6c0b56eSmrg info->BlockHandler = pScreen->BlockHandler; 216811bf0794Smrg pScreen->BlockHandler = AMDGPUBlockHandler_KMS; 2169d6c0b56eSmrg 2170d6c0b56eSmrg info->CreateScreenResources = pScreen->CreateScreenResources; 2171d6c0b56eSmrg pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS; 2172d6c0b56eSmrg 2173d6c0b56eSmrg pScreen->StartPixmapTracking = PixmapStartDirtyTracking; 2174d6c0b56eSmrg pScreen->StopPixmapTracking = PixmapStopDirtyTracking; 2175504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP 2176504d986fSmrg pScreen->SyncSharedPixmap = amdgpu_sync_shared_pixmap; 2177d6c0b56eSmrg#endif 2178d6c0b56eSmrg 2179d6c0b56eSmrg if (!xf86CrtcScreenInit(pScreen)) 2180d6c0b56eSmrg return FALSE; 2181d6c0b56eSmrg 2182d6c0b56eSmrg /* Wrap pointer motion to flip touch screen around */ 2183d6c0b56eSmrg// info->PointerMoved = pScrn->PointerMoved; 2184d6c0b56eSmrg// pScrn->PointerMoved = AMDGPUPointerMoved; 2185d6c0b56eSmrg 2186d6c0b56eSmrg if (!drmmode_setup_colormap(pScreen, pScrn)) 2187d6c0b56eSmrg return FALSE; 2188d6c0b56eSmrg 2189d6c0b56eSmrg /* Note unused options */ 2190d6c0b56eSmrg if (serverGeneration == 1) 2191d6c0b56eSmrg xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 2192d6c0b56eSmrg 219390f2b693Smrg if (info->vrr_support) { 219490f2b693Smrg if (!amdgpu_property_vectors_wrapped) { 219590f2b693Smrg saved_change_property = ProcVector[X_ChangeProperty]; 219690f2b693Smrg ProcVector[X_ChangeProperty] = amdgpu_change_property; 219790f2b693Smrg saved_delete_property = ProcVector[X_DeleteProperty]; 219890f2b693Smrg ProcVector[X_DeleteProperty] = amdgpu_delete_property; 219990f2b693Smrg amdgpu_property_vectors_wrapped = TRUE; 220090f2b693Smrg } 220190f2b693Smrg 220290f2b693Smrg amdgpu_vrr_atom = MakeAtom("_VARIABLE_REFRESH", 220390f2b693Smrg strlen("_VARIABLE_REFRESH"), TRUE); 220490f2b693Smrg } 220590f2b693Smrg 2206d6c0b56eSmrg drmmode_init(pScrn, &info->drmmode); 2207d6c0b56eSmrg 2208d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2209d6c0b56eSmrg "AMDGPUScreenInit finished\n"); 2210d6c0b56eSmrg 2211d6c0b56eSmrg return TRUE; 2212d6c0b56eSmrg} 2213d6c0b56eSmrg 221424b90cf4SmrgBool AMDGPUEnterVT_KMS(ScrnInfoPtr pScrn) 2215d6c0b56eSmrg{ 2216d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2217d6c0b56eSmrg 2218d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2219d6c0b56eSmrg "AMDGPUEnterVT_KMS\n"); 2220d6c0b56eSmrg 2221d6c0b56eSmrg amdgpu_set_drm_master(pScrn); 2222d6c0b56eSmrg 222324b90cf4Smrg if (info->shadow_fb) { 222424b90cf4Smrg int pitch; 222524b90cf4Smrg struct amdgpu_buffer *front_buffer = 222624b90cf4Smrg amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX, 222724b90cf4Smrg pScrn->virtualY, pScrn->depth, 222846845023Smrg AMDGPU_CREATE_PIXMAP_SCANOUT | 222924b90cf4Smrg AMDGPU_CREATE_PIXMAP_LINEAR, 223024b90cf4Smrg pScrn->bitsPerPixel, 223124b90cf4Smrg &pitch); 223224b90cf4Smrg 223324b90cf4Smrg if (front_buffer) { 223424b90cf4Smrg if (amdgpu_bo_map(pScrn, front_buffer) == 0) { 223524b90cf4Smrg memset(front_buffer->cpu_ptr, 0, pitch * pScrn->virtualY); 223624b90cf4Smrg amdgpu_bo_unref(&info->front_buffer); 223724b90cf4Smrg info->front_buffer = front_buffer; 223824b90cf4Smrg } else { 223924b90cf4Smrg amdgpu_bo_unref(&front_buffer); 224024b90cf4Smrg front_buffer = NULL; 224124b90cf4Smrg } 224224b90cf4Smrg } 224324b90cf4Smrg 224424b90cf4Smrg if (!front_buffer) { 224524b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 224624b90cf4Smrg "Failed to allocate new scanout BO after VT switch, " 224724b90cf4Smrg "other DRM masters may see screen contents\n"); 224824b90cf4Smrg } 224924b90cf4Smrg } 225024b90cf4Smrg 2251d6c0b56eSmrg pScrn->vtSema = TRUE; 2252d6c0b56eSmrg 2253d6c0b56eSmrg if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE)) 2254d6c0b56eSmrg return FALSE; 2255d6c0b56eSmrg 2256d6c0b56eSmrg return TRUE; 2257d6c0b56eSmrg} 2258d6c0b56eSmrg 225924b90cf4Smrgstatic void 226077d6d1ecSmrgpixmap_unref_fb(PixmapPtr pixmap) 226124b90cf4Smrg{ 226277d6d1ecSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen); 226324b90cf4Smrg struct drmmode_fb **fb_ptr = amdgpu_pixmap_get_fb_ptr(pixmap); 226477d6d1ecSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 226524b90cf4Smrg 226624b90cf4Smrg if (fb_ptr) 226724b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb_ptr, NULL); 226824b90cf4Smrg} 226924b90cf4Smrg 227077d6d1ecSmrgstatic void 227177d6d1ecSmrgclient_pixmap_unref_fb(void *value, XID id, void *pScreen) 227277d6d1ecSmrg{ 227377d6d1ecSmrg PixmapPtr pixmap = value; 227477d6d1ecSmrg 227577d6d1ecSmrg if (pixmap->drawable.pScreen == pScreen) 227677d6d1ecSmrg pixmap_unref_fb(pixmap); 227777d6d1ecSmrg} 227877d6d1ecSmrg 227924b90cf4Smrgvoid AMDGPULeaveVT_KMS(ScrnInfoPtr pScrn) 2280d6c0b56eSmrg{ 228124b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 228224b90cf4Smrg ScreenPtr pScreen = pScrn->pScreen; 2283d6c0b56eSmrg 2284d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2285d6c0b56eSmrg "AMDGPULeaveVT_KMS\n"); 2286d6c0b56eSmrg 228724b90cf4Smrg if (!info->shadow_fb) { 228824b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 228924b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 229024b90cf4Smrg xf86CrtcPtr crtc; 229124b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc; 229224b90cf4Smrg unsigned w = 0, h = 0; 229324b90cf4Smrg int i; 229424b90cf4Smrg 229577d6d1ecSmrg /* If we're called from CloseScreen, trying to clear the black 229677d6d1ecSmrg * scanout BO will likely crash and burn 229777d6d1ecSmrg */ 229877d6d1ecSmrg if (!pScreen->GCperDepth[0]) 229977d6d1ecSmrg goto hide_cursors; 230077d6d1ecSmrg 230124b90cf4Smrg /* Compute maximum scanout dimensions of active CRTCs */ 230224b90cf4Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 230324b90cf4Smrg crtc = xf86_config->crtc[i]; 230424b90cf4Smrg drmmode_crtc = crtc->driver_private; 230524b90cf4Smrg 230624b90cf4Smrg if (!drmmode_crtc->fb) 230724b90cf4Smrg continue; 230824b90cf4Smrg 230924b90cf4Smrg w = max(w, crtc->mode.HDisplay); 231024b90cf4Smrg h = max(h, crtc->mode.VDisplay); 231124b90cf4Smrg } 2312d6c0b56eSmrg 231324b90cf4Smrg /* Make all active CRTCs scan out from an all-black framebuffer */ 231424b90cf4Smrg if (w > 0 && h > 0) { 231546845023Smrg PixmapPtr black_scanout = 231646845023Smrg pScreen->CreatePixmap(pScreen, w, h, pScrn->depth, 231746845023Smrg AMDGPU_CREATE_PIXMAP_SCANOUT); 231846845023Smrg 231946845023Smrg if (black_scanout) { 232024b90cf4Smrg struct drmmode_fb *black_fb = 232146845023Smrg amdgpu_pixmap_get_fb(black_scanout); 232224b90cf4Smrg 232346845023Smrg amdgpu_pixmap_clear(black_scanout); 232424b90cf4Smrg amdgpu_glamor_finish(pScrn); 232524b90cf4Smrg 232624b90cf4Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 232724b90cf4Smrg crtc = xf86_config->crtc[i]; 232824b90cf4Smrg drmmode_crtc = crtc->driver_private; 232924b90cf4Smrg 233024b90cf4Smrg if (drmmode_crtc->fb) { 233124b90cf4Smrg if (black_fb) { 233224b90cf4Smrg drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0); 233324b90cf4Smrg } else { 233424b90cf4Smrg drmModeSetCrtc(pAMDGPUEnt->fd, 233524b90cf4Smrg drmmode_crtc->mode_crtc->crtc_id, 0, 233624b90cf4Smrg 0, 0, NULL, 0, NULL); 233724b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 233824b90cf4Smrg &drmmode_crtc->fb, NULL); 233924b90cf4Smrg } 234024b90cf4Smrg 234124b90cf4Smrg if (pScrn->is_gpu) { 234246845023Smrg if (drmmode_crtc->scanout[0]) 234346845023Smrg pixmap_unref_fb(drmmode_crtc->scanout[0]); 234446845023Smrg if (drmmode_crtc->scanout[1]) 234546845023Smrg pixmap_unref_fb(drmmode_crtc->scanout[1]); 234624b90cf4Smrg } else { 234790f2b693Smrg drmmode_crtc_scanout_free(crtc); 234824b90cf4Smrg } 234924b90cf4Smrg } 235024b90cf4Smrg } 235146845023Smrg 235246845023Smrg pScreen->DestroyPixmap(black_scanout); 235324b90cf4Smrg } 235424b90cf4Smrg } 235524b90cf4Smrg 235624b90cf4Smrg xf86RotateFreeShadow(pScrn); 235724b90cf4Smrg 235824b90cf4Smrg /* Unreference FBs of all pixmaps. After this, the only FB remaining 235924b90cf4Smrg * should be the all-black one being scanned out by active CRTCs 236024b90cf4Smrg */ 236124b90cf4Smrg for (i = 0; i < currentMaxClients; i++) { 236224b90cf4Smrg if (i > 0 && 236324b90cf4Smrg (!clients[i] || clients[i]->clientState != ClientStateRunning)) 236424b90cf4Smrg continue; 236524b90cf4Smrg 236677d6d1ecSmrg FindClientResourcesByType(clients[i], RT_PIXMAP, 236777d6d1ecSmrg client_pixmap_unref_fb, pScreen); 236824b90cf4Smrg } 236924b90cf4Smrg 237077d6d1ecSmrg pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen)); 237124b90cf4Smrg } else { 237224b90cf4Smrg memset(info->front_buffer->cpu_ptr, 0, pScrn->virtualX * 237324b90cf4Smrg info->pixel_bytes * pScrn->virtualY); 237424b90cf4Smrg } 237524b90cf4Smrg 237677d6d1ecSmrg if (pScreen->GCperDepth[0]) 237777d6d1ecSmrg TimerSet(NULL, 0, 1000, cleanup_black_fb, pScreen); 2378d6c0b56eSmrg 237977d6d1ecSmrg hide_cursors: 2380d6c0b56eSmrg xf86_hide_cursors(pScrn); 2381d6c0b56eSmrg 238224b90cf4Smrg amdgpu_drop_drm_master(pScrn); 238324b90cf4Smrg 2384d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2385d6c0b56eSmrg "Ok, leaving now...\n"); 2386d6c0b56eSmrg} 2387d6c0b56eSmrg 238824b90cf4SmrgBool AMDGPUSwitchMode_KMS(ScrnInfoPtr pScrn, DisplayModePtr mode) 2389d6c0b56eSmrg{ 2390d6c0b56eSmrg Bool ret; 2391d6c0b56eSmrg ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0); 2392d6c0b56eSmrg return ret; 2393d6c0b56eSmrg 2394d6c0b56eSmrg} 2395d6c0b56eSmrg 239624b90cf4Smrgvoid AMDGPUAdjustFrame_KMS(ScrnInfoPtr pScrn, int x, int y) 2397d6c0b56eSmrg{ 2398d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2399d6c0b56eSmrg drmmode_adjust_frame(pScrn, &info->drmmode, x, y); 2400d6c0b56eSmrg return; 2401d6c0b56eSmrg} 2402d6c0b56eSmrg 2403d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen) 2404d6c0b56eSmrg{ 2405d6c0b56eSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 240690f2b693Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2407d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2408d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2409d6c0b56eSmrg int cpp = info->pixel_bytes; 2410d6c0b56eSmrg int cursor_size; 241190f2b693Smrg int c, i; 2412d6c0b56eSmrg 2413d6c0b56eSmrg cursor_size = info->cursor_w * info->cursor_h * 4; 2414d6c0b56eSmrg cursor_size = AMDGPU_ALIGN(cursor_size, AMDGPU_GPU_PAGE_SIZE); 2415d6c0b56eSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 241690f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private; 241790f2b693Smrg 241890f2b693Smrg for (i = 0; i < 2; i++) { 241990f2b693Smrg if (!drmmode_crtc->cursor_buffer[i]) { 242090f2b693Smrg drmmode_crtc->cursor_buffer[i] = 242190f2b693Smrg amdgpu_bo_open(pAMDGPUEnt->pDev, 242290f2b693Smrg cursor_size, 0, 242390f2b693Smrg AMDGPU_GEM_DOMAIN_VRAM); 242490f2b693Smrg 242590f2b693Smrg if (!(drmmode_crtc->cursor_buffer[i])) { 2426d6c0b56eSmrg ErrorF("Failed to allocate cursor buffer memory\n"); 2427d6c0b56eSmrg return FALSE; 2428d6c0b56eSmrg } 2429d6c0b56eSmrg 243090f2b693Smrg if (amdgpu_bo_cpu_map(drmmode_crtc->cursor_buffer[i]->bo.amdgpu, 243190f2b693Smrg &drmmode_crtc->cursor_buffer[i]->cpu_ptr)) 2432d6c0b56eSmrg ErrorF("Failed to map cursor buffer memory\n"); 2433d6c0b56eSmrg } 2434d6c0b56eSmrg } 2435d6c0b56eSmrg } 2436d6c0b56eSmrg 243735d5b7c7Smrg if (!info->front_buffer) { 2438d6c0b56eSmrg int pitch; 243946845023Smrg int hint = AMDGPU_CREATE_PIXMAP_SCANOUT; 2440d6c0b56eSmrg 2441d6c0b56eSmrg if (info->shadow_primary) 244246845023Smrg hint |= AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2443d6c0b56eSmrg else if (!info->use_glamor) 244446845023Smrg hint |= AMDGPU_CREATE_PIXMAP_LINEAR; 2445d6c0b56eSmrg 2446d6c0b56eSmrg info->front_buffer = 2447d6c0b56eSmrg amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX, 2448d6c0b56eSmrg pScrn->virtualY, pScrn->depth, 2449d6c0b56eSmrg hint, pScrn->bitsPerPixel, 2450d6c0b56eSmrg &pitch); 2451d6c0b56eSmrg if (!(info->front_buffer)) { 2452d6c0b56eSmrg ErrorF("Failed to allocate front buffer memory\n"); 2453d6c0b56eSmrg return FALSE; 2454d6c0b56eSmrg } 2455d6c0b56eSmrg 2456d6c0b56eSmrg if (!info->use_glamor && 2457d6c0b56eSmrg amdgpu_bo_map(pScrn, info->front_buffer) != 0) { 2458d6c0b56eSmrg ErrorF("Failed to map front buffer memory\n"); 2459d6c0b56eSmrg return FALSE; 2460d6c0b56eSmrg } 2461d6c0b56eSmrg 2462d6c0b56eSmrg pScrn->displayWidth = pitch / cpp; 2463d6c0b56eSmrg } 2464d6c0b56eSmrg 2465d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer pitch: %d bytes\n", 2466d6c0b56eSmrg pScrn->displayWidth * cpp); 2467d6c0b56eSmrg return TRUE; 2468d6c0b56eSmrg} 2469d6c0b56eSmrg 2470d6c0b56eSmrg/* Used to disallow modes that are not supported by the hardware */ 247124b90cf4SmrgModeStatus AMDGPUValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode, 2472d6c0b56eSmrg Bool verbose, int flag) 2473d6c0b56eSmrg{ 2474d6c0b56eSmrg /* There are problems with double scan mode at high clocks 2475d6c0b56eSmrg * They're likely related PLL and display buffer settings. 2476d6c0b56eSmrg * Disable these modes for now. 2477d6c0b56eSmrg */ 2478d6c0b56eSmrg if (mode->Flags & V_DBLSCAN) { 2479d6c0b56eSmrg if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768)) 2480d6c0b56eSmrg return MODE_CLOCK_RANGE; 2481d6c0b56eSmrg } 2482d6c0b56eSmrg return MODE_OK; 2483d6c0b56eSmrg} 2484