diff --git a/src/i830.h b/src/i830.h index 20bcde66..6c03a73f 100644 --- a/src/i830.h +++ b/src/i830.h @@ -196,6 +196,8 @@ extern const char *i830_output_type_names[]; typedef struct _I830CrtcPrivateRec { int pipe; Bool gammaEnabled; + Rotation rotation; /* current rotation, mirror from pI830->rotation */ + Rotation rotations; /* all */ } I830CrtcPrivateRec, *I830CrtcPrivatePtr; #define I830CrtcPrivate(c) ((I830CrtcPrivatePtr) (c)->driver_private) diff --git a/src/i830_display.c b/src/i830_display.c index c5880d6b..b70f1ebd 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -821,7 +821,9 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, ((adjusted_mode->CrtcVBlankEnd - 1) << 16)); OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) | ((adjusted_mode->CrtcVSyncEnd - 1) << 16)); - OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp); + /* XXX we might always set real line stride, rotation can change it */ + // OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp); + OUTREG(dspstride_reg, pI830->displayWidth * pI830->cpp); /* pipesrc and dspsize control the size that is scaled from, which should * always be the user's requested size. */ diff --git a/src/i830_driver.c b/src/i830_driver.c index 23729de5..5e66038c 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2950,11 +2950,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) shadowSetup(pScreen); /* support all rotations */ xf86RandR12Init (pScreen); - if (IS_I965G(pI830)) { - xf86RandR12SetRotations (pScreen, RR_Rotate_0); /* only 0 degrees for I965G */ - } else { - xf86RandR12SetRotations (pScreen, RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270); - } + xf86RandR12SetRotations (pScreen, RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270); pI830->PointerMoved = pScrn->PointerMoved; pScrn->PointerMoved = I830PointerMoved; pI830->CreateScreenResources = pScreen->CreateScreenResources; diff --git a/src/i830_randr.c b/src/i830_randr.c index 3d6febc1..019e71c4 100644 --- a/src/i830_randr.c +++ b/src/i830_randr.c @@ -333,6 +333,14 @@ xf86RandR12GetRotation(ScreenPtr pScreen) return randrp->rotation; } +Rotation +xf86RandR12GetRotation12(RRCrtcPtr randr_crtc) +{ + xf86CrtcPtr crtc = randr_crtc->devPrivate; + I830CrtcPrivatePtr intel_crtc = I830CrtcPrivate(crtc); + return intel_crtc->rotation; +} + Bool xf86RandR12CreateScreenResources (ScreenPtr pScreen) { @@ -422,12 +430,29 @@ xf86RandR12Init (ScreenPtr pScreen) return TRUE; } +/* RandR12 should have been initialized, so we might set rotations + to Crtc object. + */ void xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations) { XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); +#if RANDR_12_INTERFACE + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; +#endif randrp->supported_rotations = rotations; +#if RANDR_12_INTERFACE + for (c = 0; c < config->num_crtc ; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + I830CrtcPrivatePtr intel_crtc = I830CrtcPrivate(crtc); + crtc->randr_crtc->rotations = rotations; + intel_crtc->rotations = rotations; + intel_crtc->rotation = RR_Rotate_0; /*XXX initial rotation fix */ + } +#endif } void @@ -468,11 +493,13 @@ xf86RandR12ScreenSetSize (ScreenPtr pScreen, } if (pRoot) (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); - pScrn->virtualX = width; - pScrn->virtualY = height; - - pScreen->width = pScrn->virtualX; - pScreen->height = pScrn->virtualY; + /* XXX don't change the actual draw window size */ + /*pScrn->virtualX = width; + *pScrn->virtualY = height; + *pScreen->width = pScrn->virtualX; + *pScreen->height = pScrn->virtualY;*/ + pScreen->width = width; + pScreen->height = height; pScreen->mmWidth = mmWidth; pScreen->mmHeight = mmHeight; @@ -509,7 +536,7 @@ xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) return FALSE; x = crtc->x; y = crtc->y; - rotation = RR_Rotate_0; + rotation = xf86RandR12GetRotation12(randr_crtc); numOutputs = 0; randr_mode = NULL; for (i = 0; i < config->num_output; i++) @@ -540,6 +567,9 @@ xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) return ret; } +extern Bool i830RandR12Rotate(ScreenPtr pScreen, RRCrtcPtr randr_crtc, + DisplayModePtr mode, Rotation rotation); + static Bool xf86RandR12CrtcSet (ScreenPtr pScreen, RRCrtcPtr randr_crtc, @@ -556,6 +586,8 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, DisplayModePtr mode = randr_mode ? randr_mode->devPrivate : NULL; Bool changed = FALSE; Bool pos_changed; + Bool rotation_changed = FALSE; + Rotation old_rotation; int o, ro; xf86CrtcPtr *save_crtcs; Bool save_enabled = crtc->enabled; @@ -569,6 +601,14 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, pos_changed = changed; if (x != crtc->x || y != crtc->y) pos_changed = TRUE; + + old_rotation = xf86RandR12GetRotation12(randr_crtc); + if (rotation != old_rotation) { + changed = TRUE; + rotation_changed = TRUE; + pos_changed = TRUE; + } + for (o = 0; o < config->num_output; o++) { xf86OutputPtr output = config->output[o]; @@ -604,6 +644,14 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, pI830->AccelInfoRec->NeedToSync = FALSE; } + /* rotation should take effect when crtc enabled*/ + if (rotation_changed && crtc->enabled) { + randr_crtc->rotation = rotation; + if (!i830RandR12Rotate(pScreen, randr_crtc, mode, rotation)) { + randr_crtc->rotation = old_rotation; + } + } + if (mode) { if (!i830PipeSetMode (crtc, mode, TRUE)) diff --git a/src/i830_rotate.c b/src/i830_rotate.c index b2587b26..1f1824b6 100644 --- a/src/i830_rotate.c +++ b/src/i830_rotate.c @@ -60,9 +60,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i830.h" #include "i915_reg.h" #include "i915_3d.h" +#include "i830_xf86Crtc.h" +#include "i830_randr.h" + #include "brw_defines.h" #include "brw_structs.h" - #ifdef XF86DRI #include "dri.h" #endif @@ -1341,6 +1343,268 @@ I830UpdateRotate (ScreenPtr pScreen, #endif } +static +Bool i830_setup_shadowfb(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = I830CrtcPrivate(crtc); + ShadowUpdateProc func = NULL; + + if (pI830->noAccel) + func = LoaderSymbol("shadowUpdateRotatePacked"); + else { + if (IS_I9XX(pI830)) { + if (IS_I965G(pI830)) + func = I965UpdateRotate; + else + func = I915UpdateRotate; + } else + func = I830UpdateRotate; + } + + if (!func) + return FALSE; + + shadowRemove (pScrn->pScreen, NULL); + if (intel_crtc->rotation != RR_Rotate_0) { + shadowAdd (pScrn->pScreen, + (*pScrn->pScreen->GetScreenPixmap) (pScrn->pScreen), + func, I830WindowLinear, intel_crtc->rotation, 0); + } + + if (intel_crtc->rotation != RR_Rotate_0) + pScrn->fbOffset = pI830->RotatedMem.Start; + else + pScrn->fbOffset = pI830->FrontBuffer.Start; + + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + + pScrn->pScreen->ModifyPixmapHeader((*pScrn->pScreen->GetScreenPixmap)(pScrn->pScreen), + pScrn->pScreen->width, + pScrn->pScreen->height, + pScrn->pScreen->rootDepth, pScrn->bitsPerPixel, + PixmapBytePad(pScrn->displayWidth, pScrn->pScreen->rootDepth), + (pointer)(pI830->FbBase + pScrn->fbOffset)); + (*pScrn->EnableDisableFBAccess) (pScrn->pScreen->myNum, FALSE); + (*pScrn->EnableDisableFBAccess) (pScrn->pScreen->myNum, TRUE); + + return TRUE; +} + +static +Bool i830_rotate_mem_realloc(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = I830CrtcPrivate(crtc); +#ifdef XF86DRI + Bool didLock = FALSE; +#endif + int i; + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + didLock = I830DRILock(pScrn); + + /* Do heap teardown here + */ + if (pI830->mmModeFlags & I830_KERNEL_TEX) { + drmI830MemDestroyHeap destroy; + destroy.region = I830_MEM_REGION_AGP; + + if (drmCommandWrite(pI830->drmSubFD, + DRM_I830_DESTROY_HEAP, + &destroy, sizeof(destroy))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[dri] I830 destroy heap failed\n"); + } + } + + if (pI830->mmModeFlags & I830_KERNEL_TEX) { + if (pI830->TexMem.Key != -1) + xf86UnbindGARTMemory(pScrn->scrnIndex, pI830->TexMem.Key); + I830FreeVidMem(pScrn, &(pI830->TexMem)); + } + if (pI830->StolenPool.Allocated.Key != -1) { + xf86UnbindGARTMemory(pScrn->scrnIndex, pI830->StolenPool.Allocated.Key); + xf86DeallocateGARTMemory(pScrn->scrnIndex, pI830->StolenPool.Allocated.Key); + } + if (pI830->DepthBuffer.Key != -1) + xf86UnbindGARTMemory(pScrn->scrnIndex, pI830->DepthBuffer.Key); + I830FreeVidMem(pScrn, &(pI830->DepthBuffer)); + if (pI830->BackBuffer.Key != -1) + xf86UnbindGARTMemory(pScrn->scrnIndex, pI830->BackBuffer.Key); + I830FreeVidMem(pScrn, &(pI830->BackBuffer)); + } +#endif + + if (pI830->RotatedMem.Key != -1) + xf86UnbindGARTMemory(pScrn->scrnIndex, pI830->RotatedMem.Key); + + I830FreeVidMem(pScrn, &(pI830->RotatedMem)); + memset(&(pI830->RotatedMem), 0, sizeof(pI830->RotatedMem)); + pI830->RotatedMem.Key = -1; + + if (IS_I965G(pI830)) { + if (pI830->RotateStateMem.Key != -1) + xf86UnbindGARTMemory(pScrn->scrnIndex, pI830->RotateStateMem.Key); + + I830FreeVidMem(pScrn, &(pI830->RotateStateMem)); + memset(&(pI830->RotateStateMem), 0, sizeof(pI830->RotateStateMem)); + pI830->RotateStateMem.Key = -1; + } + + if (intel_crtc->rotation != RR_Rotate_0) { + if (!I830AllocateRotatedBuffer(pScrn, pI830->disableTiling ? ALLOC_NO_TILING : 0)) + goto BAIL1; + + I830FixOffset(pScrn, &(pI830->RotatedMem)); + if (pI830->RotatedMem.Key != -1) + xf86BindGARTMemory(pScrn->scrnIndex, pI830->RotatedMem.Key, pI830->RotatedMem.Offset); + if (IS_I965G(pI830)) { + I830FixOffset(pScrn, &(pI830->RotateStateMem)); + if (pI830->RotateStateMem.Key != -1) + xf86BindGARTMemory(pScrn->scrnIndex, pI830->RotateStateMem.Key, + pI830->RotateStateMem.Offset); + } + } + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + if (!I830AllocateBackBuffer(pScrn, + pI830->disableTiling ? ALLOC_NO_TILING : 0)) + goto BAIL2; + + if (!I830AllocateDepthBuffer(pScrn, + pI830->disableTiling ? ALLOC_NO_TILING : 0)) + goto BAIL3; + + if (pI830->mmModeFlags & I830_KERNEL_TEX) { + if (!I830AllocateTextureMemory(pScrn, + pI830->disableTiling ? ALLOC_NO_TILING : 0)) + goto BAIL4; + } + + I830DoPoolAllocation(pScrn, &(pI830->StolenPool)); + + I830FixOffset(pScrn, &(pI830->BackBuffer)); + I830FixOffset(pScrn, &(pI830->DepthBuffer)); + + if (pI830->BackBuffer.Key != -1) + xf86BindGARTMemory(pScrn->scrnIndex, pI830->BackBuffer.Key, pI830->BackBuffer.Offset); + if (pI830->DepthBuffer.Key != -1) + xf86BindGARTMemory(pScrn->scrnIndex, pI830->DepthBuffer.Key, pI830->DepthBuffer.Offset); + if (pI830->StolenPool.Allocated.Key != -1) + xf86BindGARTMemory(pScrn->scrnIndex, pI830->StolenPool.Allocated.Key, pI830->StolenPool.Allocated.Offset); + if (pI830->mmModeFlags & I830_KERNEL_TEX) { + if (pI830->TexMem.Key != -1) + xf86BindGARTMemory(pScrn->scrnIndex, pI830->TexMem.Key, pI830->TexMem.Offset); + } + I830SetupMemoryTiling(pScrn); + /* update fence registers */ + if (IS_I965G(pI830)) { + for (i = 0; i < FENCE_NEW_NR; i++) { + OUTREG(FENCE_NEW + i * 8, pI830->ModeReg.Fence[i]); + OUTREG(FENCE_NEW + 4 + i * 8, pI830->ModeReg.Fence[i+FENCE_NEW_NR]); + } + } else { + for (i = 0; i < 8; i++) + OUTREG(FENCE + i * 4, pI830->ModeReg.Fence[i]); + } + + { + drmI830Sarea *sarea = DRIGetSAREAPrivate(pScrn->pScreen); + I830UpdateDRIBuffers(pScrn, sarea ); + } + + if (didLock) + I830DRIUnlock(pScrn); + } +#endif + + return TRUE; +BAIL1: +BAIL2: +BAIL3: +BAIL4: + //XXX alloc failure + return FALSE; +} + +Bool +i830RandR12Rotate(ScreenPtr pScreen, RRCrtcPtr randr_crtc, + DisplayModePtr mode, Rotation rotation) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc = randr_crtc->devPrivate; + I830CrtcPrivatePtr intel_crtc = I830CrtcPrivate(crtc); + Rotation old_rotation = intel_crtc->rotation; + + if (old_rotation == rotation) + return TRUE; + intel_crtc->rotation = rotation; + pI830->rotation = rotation; + + *pI830->used3D |= 1<<31; /* use high bit to denote new rotation occured */ + + + /* user should have already changed screen size. */ + /* pI830->displayWidth should always trigger current width in use, + pScrn->displayWidth is current config in use. */ + switch (intel_crtc->rotation) { + case RR_Rotate_0: + ErrorF("Rotating Screen to 0 degrees\n"); + pScrn->displayWidth = pI830->displayWidth; + break; + case RR_Rotate_90: + ErrorF("Rotating Screen to 90 degrees\n"); + pScrn->displayWidth = pScrn->pScreen->width; + break; + case RR_Rotate_180: + ErrorF("Rotating Screen to 180 degrees\n"); + pScrn->displayWidth = pI830->displayWidth; + break; + case RR_Rotate_270: + ErrorF("Rotating Screen to 270 degrees\n"); + pScrn->displayWidth = pScrn->pScreen->width; + break; + } + ErrorF("pScrn->displayWidth %d\n", pScrn->displayWidth); + + if (!i830_rotate_mem_realloc(pScrn, crtc)) { + intel_crtc->rotation = old_rotation; + return FALSE; + } + + if (!i830_setup_shadowfb(pScrn, crtc)) { + intel_crtc->rotation = old_rotation; + return FALSE; + } + + +#ifdef I830_USE_XAA + if (pI830->AccelInfoRec != NULL) { + /* Don't allow pixmap cache or offscreen pixmaps when rotated */ + /* XAA needs some serious fixing for this to happen */ + if (intel_crtc->rotation == RR_Rotate_0) { + pI830->AccelInfoRec->Flags = LINEAR_FRAMEBUFFER | OFFSCREEN_PIXMAPS | + PIXMAP_CACHE; + pI830->AccelInfoRec->UsingPixmapCache = TRUE; + /* funny as it seems this will enable XAA's createpixmap */ + pI830->AccelInfoRec->maxOffPixWidth = 0; + pI830->AccelInfoRec->maxOffPixHeight = 0; + } else { + pI830->AccelInfoRec->Flags = LINEAR_FRAMEBUFFER; + pI830->AccelInfoRec->UsingPixmapCache = FALSE; + /* funny as it seems this will disable XAA's createpixmap */ + pI830->AccelInfoRec->maxOffPixWidth = 1; + pI830->AccelInfoRec->maxOffPixHeight = 1; + } + } +#endif + return TRUE; +} + Bool I830Rotate(ScrnInfoPtr pScrn, DisplayModePtr mode) { diff --git a/src/i830_xf86Crtc.c b/src/i830_xf86Crtc.c index 0c482a2e..6e836bdf 100644 --- a/src/i830_xf86Crtc.c +++ b/src/i830_xf86Crtc.c @@ -517,6 +517,7 @@ xf86SetScrnInfoModes (ScrnInfoPtr pScrn) xf86CrtcPtr crtc; DisplayModePtr last, mode; int originalVirtualX, originalVirtualY; + I830Ptr pI830 = I830PTR(pScrn); output = config->output[config->compat_output]; if (!output->crtc) @@ -549,9 +550,10 @@ xf86SetScrnInfoModes (ScrnInfoPtr pScrn) /* Disable modes in the XFree86 DDX list that are larger than the current * virtual size. */ + /* pass real line pitch, rotation might change this */ i830xf86ValidateModesSize(pScrn, pScrn->modes, originalVirtualX, originalVirtualY, - pScrn->displayWidth); + pI830->displayWidth); /* Strip out anything that we threw out for virtualX/Y. */ i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE);