VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispDrawCmd.cpp@ 37423

Last change on this file since 37423 was 37423, checked in by vboxsync, 14 years ago

Ran the source code massager (scm).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.8 KB
Line 
1/* $Id: VBoxDispDrawCmd.cpp 37423 2011-06-12 18:37:56Z vboxsync $ */
2
3/** @file
4 * VBox XPDM Display driver drawing interface functions
5 */
6
7/*
8 * Copyright (C) 2011 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/* The driver operates in 3 modes:
20 * 1) BASE : Driver does not report to host about any operations.
21 * All Drv* are immediately routed to Eng*.
22 * 2) VBVA : Driver reports dirty rectangles to host.
23 * 3) VBVA + VRDP : Driver also creates orders pipeline from which VRDP
24 * can reconstruct all drawing operations, including
25 * bitmap updates.
26 *
27 * These modes affect only VBoxDispDrv* functions in this file.
28 *
29 * VBVA mode is enabled by a registry key for the miniport driver
30 * (as it is implemented now).
31 *
32 * VRDP mode is enabled when a VRDP client connects and VBVA is enabled.
33 * The host sets a bit flag in VBVAMemory when VRDP client is connected.
34 *
35 * The VRDP mode pipeline consists of 3 types of commands:
36 *
37 * 1) RDP orders: BitBlt, RectFill, Text.
38 * These are the simplest ones.
39 *
40 * 2) Caching: Bitmap, glyph, brush.
41 * The driver maintains a bitmap (or other objects) cache.
42 * All source bitmaps are cached. The driver verifies
43 * iUniq and also computes CRC for these bitmaps
44 * for searching. The driver will use SURFOBJ::dhsurf
45 * field to save a pointer to in driver structure, even
46 * for Engine managed bitmaps (hope that will work).
47 *
48 *
49 * 3) Bitmap updates, when given draw operation can not be done
50 * using orders.
51 *
52 */
53
54#include "VBoxDisp.h"
55#include "VBoxDispDrawCmd.h"
56
57typedef struct _VBOXDISPCALLSTATS
58{
59 ULONG VBoxDispDrvLineTo;
60 ULONG VBoxDispDrvStrokePath;
61 ULONG VBoxDispDrvFillPath;
62 ULONG VBoxDispDrvTextOut;
63 ULONG VBoxDispDrvPaint;
64 ULONG VBoxDispDrvSaveScreenBits;
65 ULONG VBoxDispDrvBitBlt;
66 ULONG VBoxDispDrvStretchBlt;
67 ULONG VBoxDispDrvCopyBits;
68} VBOXDISPCALLSTATS;
69
70static VBOXDISPCALLSTATS gDispCallStats = {0,0,0,0,0,0,0,0,0};
71
72#ifdef STAT_sunlover
73# define STATDRVENTRY(a, b) do {if (VBoxDispIsScreenSurface(b)) gDispCallStats.VBoxDispDrv##a++; } while (0)
74# define STATPRINT do {VBoxDispPrintStats();} while (0)
75# define DUMPSURF(_s, _name) VBoxDispDumpPSO(_s, _name);
76#else
77# define STATDRVENTRY(a, b)
78# define STATPRINT
79# define DUMPSURF(_s, _name)
80#endif
81
82#define VBVA_OPERATION(__psoDest, __fn, __a) do { \
83 if (VBoxDispIsScreenSurface(__psoDest)) \
84 { \
85 PVBOXDISPDEV pDev = (PVBOXDISPDEV)__psoDest->dhpdev; \
86 \
87 if ( pDev->hgsmi.bSupported \
88 && VBoxVBVABufferBeginUpdate(&pDev->vbvaCtx, &pDev->hgsmi.ctx)) \
89 { \
90 vbvaDrv##__fn __a; \
91 \
92 if ( pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents \
93 & VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET) \
94 { \
95 vrdpReset(pDev); \
96 \
97 pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents &= \
98 ~VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET; \
99 } \
100 \
101 if (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents \
102 & VBVA_F_MODE_VRDP) \
103 { \
104 vrdpDrv##__fn __a; \
105 } \
106 \
107 VBoxVBVABufferEndUpdate(&pDev->vbvaCtx); \
108 } \
109 } \
110} while (0)
111
112BOOL VBoxDispIsScreenSurface(SURFOBJ *pso)
113{
114 if (pso)
115 {
116 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
117
118 /* The screen surface has the 'pso->dhpdev' field,
119 * and is either the screen device surface with handle = hsurfScreen,
120 * or a surface derived from DDRAW with address equal to the framebuffer.
121 */
122 if (pDev && (pso->hsurf == pDev->surface.hSurface || pso->pvBits == pDev->memInfo.FrameBufferBase))
123 {
124 return TRUE;
125 }
126 }
127
128 return FALSE;
129}
130
131static void VBoxDispPrintStats(void)
132{
133 LOG(("LineTo = %u\n",
134 "StrokePath = %u\n",
135 "FillPath = %u\n",
136 "TextOut = %u\n",
137 "DrvPaint = %u\n",
138 "SaveScreenBits = %u\n",
139 "BitBlt = %u\n",
140 "StretchBlt = %u\n",
141 "CopyBits = %u",
142 gDispCallStats.VBoxDispDrvLineTo,
143 gDispCallStats.VBoxDispDrvStrokePath,
144 gDispCallStats.VBoxDispDrvFillPath,
145 gDispCallStats.VBoxDispDrvTextOut,
146 gDispCallStats.VBoxDispDrvPaint,
147 gDispCallStats.VBoxDispDrvSaveScreenBits,
148 gDispCallStats.VBoxDispDrvBitBlt,
149 gDispCallStats.VBoxDispDrvStretchBlt,
150 gDispCallStats.VBoxDispDrvCopyBits
151 ));
152}
153
154void VBoxDispDumpPSO(SURFOBJ *pso, char *s)
155{
156 if (pso)
157 {
158 LOG(("Surface %s: %p\n"
159 " DHSURF dhsurf = %p\n"
160 " HSURF hsurf = %p\n"
161 " DHPDEV dhpdev = %p\n"
162 " HDEV hdev = %p\n"
163 " SIZEL sizlBitmap = %dx%d\n"
164 " ULONG cjBits = %p\n"
165 " PVOID pvBits = %p\n"
166 " PVOID pvScan0 = %p\n"
167 " LONG lDelta = %p\n"
168 " ULONG iUniq = %p\n"
169 " ULONG iBitmapFormat = %p\n"
170 " USHORT iType = %p\n"
171 " USHORT fjBitmap = %p",
172 s, pso, pso->dhsurf, pso->hsurf, pso->dhpdev, pso->hdev,
173 pso->sizlBitmap.cx, pso->sizlBitmap.cy, pso->cjBits, pso->pvBits,
174 pso->pvScan0, pso->lDelta, pso->iUniq, pso->iBitmapFormat, pso->iType, pso->fjBitmap));
175 }
176 else
177 {
178 LOG(("Surface %s: %p", s, pso));
179 }
180}
181
182static void ssbDiscardTopSlot(PVBOXDISPDEV pDev)
183{
184 SSB *pSSB = &pDev->aSSB[--pDev->cSSB];
185
186 if (pSSB->pBuffer)
187 {
188 EngFreeMem (pSSB->pBuffer);
189 pSSB->pBuffer = NULL;
190 }
191
192 pSSB->ident = 0;
193}
194
195static void ssbDiscardUpperSlots(PVBOXDISPDEV pDev, ULONG_PTR ident)
196{
197 while (pDev->cSSB > ident)
198 {
199 ssbDiscardTopSlot (pDev);
200 }
201}
202
203static BOOL ssbCopy(SSB *pSSB, SURFOBJ *pso, RECTL *prcl, BOOL bToScreen)
204{
205 BYTE *pSrc;
206 BYTE *pDst;
207
208 LONG lDeltaSrc;
209 LONG lDeltaDst;
210
211 ULONG cWidth;
212 ULONG cHeight;
213
214 int cbPixel = format2BytesPerPixel(pso);
215
216 LOGF(("pSSB = %p, pso = %p, prcl = %p, bToScreen = %d", pSSB, pso, prcl, bToScreen));
217
218 if (cbPixel == 0)
219 {
220 WARN(("unsupported pixel format!!!"));
221 return FALSE;
222 }
223
224 cWidth = prcl->right - prcl->left;
225 cHeight = prcl->bottom - prcl->top;
226
227 if (bToScreen)
228 {
229 if (pSSB->pBuffer == NULL)
230 {
231 WARN(("source buffer is NULL!!!"));
232 return FALSE;
233 }
234
235 pSrc = pSSB->pBuffer;
236 lDeltaSrc = cWidth * cbPixel;
237
238 pDst = (BYTE *)pso->pvScan0 +
239 pso->lDelta * prcl->top +
240 cbPixel * prcl->left;
241 lDeltaDst = pso->lDelta;
242 }
243 else
244 {
245 if (pSSB->pBuffer != NULL)
246 {
247 WARN(("source buffer is not NULL!!!"));
248 return FALSE;
249 }
250
251 pSSB->pBuffer = (BYTE *)EngAllocMem (0, cWidth * cHeight * cbPixel, MEM_ALLOC_TAG);
252
253 if (pSSB->pBuffer == NULL)
254 {
255 WARN(("Failed to allocate buffer!!!"));
256 return FALSE;
257 }
258
259 pDst = pSSB->pBuffer;
260 lDeltaDst = cWidth * cbPixel;
261
262 pSrc = (BYTE *)pso->pvScan0 +
263 pso->lDelta * prcl->top +
264 cbPixel * prcl->left;
265 lDeltaSrc = pso->lDelta;
266 }
267
268 LOG(("cHeight = %d, pDst = %p, pSrc = %p, lDeltaSrc = %d, lDeltaDst = %d",
269 cHeight, pDst, pSrc, lDeltaSrc, lDeltaDst));
270
271 while (cHeight--)
272 {
273 memcpy (pDst, pSrc, cWidth * cbPixel);
274
275 pDst += lDeltaDst;
276 pSrc += lDeltaSrc;
277 }
278
279 LOGF(("completed."));
280 return TRUE;
281}
282
283/*
284 * Display driver callbacks.
285 */
286
287BOOL APIENTRY
288VBoxDispDrvLineTo(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, LONG x1, LONG y1, LONG x2, LONG y2,
289 RECTL *prclBounds, MIX mix)
290{
291 BOOL bRc;
292 LOGF_ENTER();
293 STATDRVENTRY(LineTo, pso);
294
295 bRc = EngLineTo(getSurfObj(pso), pco, pbo, x1, y1, x2, y2, prclBounds, mix);
296 VBVA_OPERATION(pso, LineTo, (pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix));
297
298 LOGF_LEAVE();
299 return bRc;
300}
301
302BOOL APIENTRY
303VBoxDispDrvStrokePath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo,
304 BRUSHOBJ *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix)
305{
306 BOOL bRc;
307 LOGF_ENTER();
308 STATDRVENTRY(StrokePath, pso);
309
310 bRc = EngStrokePath(getSurfObj(pso), ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix);
311 VBVA_OPERATION(pso, StrokePath, (pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix));
312
313 LOGF_LEAVE();
314 return bRc;
315}
316
317BOOL APIENTRY
318VBoxDispDrvFillPath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg,
319 MIX mix, FLONG flOptions)
320{
321 BOOL bRc;
322 LOGF_ENTER();
323 STATDRVENTRY(FillPath, pso);
324
325 bRc = EngFillPath(getSurfObj(pso), ppo, pco, pbo, pptlBrushOrg, mix, flOptions);
326 VBVA_OPERATION(pso, FillPath, (pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions));
327
328 LOGF_LEAVE();
329 return bRc;
330}
331
332BOOL APIENTRY VBoxDispDrvPaint(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix)
333{
334 BOOL bRc;
335 LOGF_ENTER();
336 STATDRVENTRY(Paint, pso);
337
338 bRc = EngPaint (getSurfObj(pso), pco, pbo, pptlBrushOrg, mix);
339 VBVA_OPERATION(pso, Paint, (pso, pco, pbo, pptlBrushOrg, mix));
340
341 LOGF_LEAVE();
342 return bRc;
343}
344
345BOOL APIENTRY
346VBoxDispDrvTextOut(SURFOBJ *pso, STROBJ *pstro, FONTOBJ *pfo, CLIPOBJ *pco,
347 RECTL *prclExtra, RECTL *prclOpaque, BRUSHOBJ *pboFore,
348 BRUSHOBJ *pboOpaque, POINTL *pptlOrg, MIX mix)
349{
350 BOOL bRc;
351 LOGF_ENTER();
352 STATDRVENTRY(TextOut, pso);
353
354 bRc = EngTextOut(getSurfObj(pso), pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix);
355 VBVA_OPERATION(pso, TextOut, (pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix));
356
357 LOGF_LEAVE();
358 return bRc;
359}
360
361ULONG_PTR APIENTRY VBoxDispDrvSaveScreenBits(SURFOBJ *pso, ULONG iMode, ULONG_PTR ident, RECTL *prcl)
362{
363 ULONG_PTR rc = 0; /* 0 means the function failure for every iMode. */
364 RECTL rcl;
365 SSB *pSSB;
366 SURFOBJ *psoOrg = pso;
367 BOOL bCallVBVA = FALSE;
368
369 PVBOXDISPDEV pDev = (PVBOXDISPDEV) pso->dhpdev;
370
371 LOGF(("%p, %d, %d, %d,%d %d,%d", pso, iMode, ident, prcl->left, prcl->top, prcl->right, prcl->bottom));
372
373 if (!pDev)
374 {
375 return rc;
376 }
377
378 pso = getSurfObj(pso);
379
380 /* Order the rectangle. */
381 if (prcl->left <= prcl->right)
382 {
383 rcl.left = prcl->left;
384 rcl.right = prcl->right;
385 }
386 else
387 {
388 rcl.left = prcl->right;
389 rcl.right = prcl->left;
390 }
391
392 if (prcl->top <= prcl->bottom)
393 {
394 rcl.top = prcl->top;
395 rcl.bottom = prcl->bottom;
396 }
397 else
398 {
399 rcl.top = prcl->bottom;
400 rcl.bottom = prcl->top;
401 }
402
403 /* Implementation of the save/restore is a bit complicated because RDP
404 * requires "the sequencing of saves and restores is such that they
405 * behave as a last-in, first-out stack.".
406 */
407 switch (iMode)
408 {
409 case SS_SAVE:
410 {
411 LOG(("SS_SAVE %d", pDev->cSSB));
412
413 if (pDev->cSSB >= RT_ELEMENTS(pDev->aSSB))
414 {
415 /* All slots are already in use. Fail. */
416 WARN(("no more slots %d!!!", pDev->cSSB));
417 break;
418 }
419
420 /* Get pointer to the slot where bits will be saved. */
421 pSSB = &pDev->aSSB[pDev->cSSB];
422
423 /* Allocate memory for screen bits and copy them to the buffer. */
424 if (ssbCopy(pSSB, pso, &rcl, FALSE /* bToScreen */))
425 {
426 /* Bits where successfully copied. Increase the active slot number
427 * and call VBVA levels, 'ident' is also assigned, the VBVA level
428 * will use it even for the SS_SAVE.
429 */
430 ident = rc = pSSB->ident = ++pDev->cSSB;
431 bCallVBVA = TRUE;
432 }
433 } break;
434
435 case SS_RESTORE:
436 {
437 LOG(("SS_RESTORE"));
438
439 if (pDev->cSSB == 0 || ident == 0 || ident > pDev->cSSB)
440 {
441 WARN(("no slot: pDev->cSSB = %d!!!", pDev->cSSB));
442 break;
443 }
444
445 if (ident < pDev->cSSB)
446 {
447 ssbDiscardUpperSlots(pDev, ident);
448 }
449
450 Assert(ident == pDev->cSSB);
451 Assert(ident != 0);
452
453 pSSB = &pDev->aSSB[ident - 1];
454
455 ssbCopy(pSSB, pso, &rcl, TRUE /* bToScreen */);
456
457 /* Bits must be discarded. */
458 ssbDiscardTopSlot (pDev);
459
460 rc = TRUE;
461 bCallVBVA = TRUE;
462 } break;
463
464 case SS_FREE:
465 {
466 LOG(("SS_FREE"));
467
468 if (pDev->cSSB == 0 || ident == 0 || ident > pDev->cSSB)
469 {
470 WARN(("no slot: pDev->cSSB = %d!!!", pDev->cSSB));
471 break;
472 }
473
474 if (ident < pDev->cSSB)
475 {
476 ssbDiscardUpperSlots(pDev, ident);
477 }
478
479 Assert(ident == pDev->cSSB);
480 Assert(ident != 0);
481
482 /* Bits must be discarded. */
483 ssbDiscardTopSlot(pDev);
484
485 rc = TRUE;
486 } break;
487 }
488
489 /* Now call the VBVA/VRDP levels. */
490 if (bCallVBVA)
491 {
492 LOG(("calling VBVA"));
493 VBVA_OPERATION(psoOrg, SaveScreenBits, (psoOrg, iMode, ident, &rcl));
494 }
495
496 LOGF(("return %d", rc));
497 return rc;
498}
499
500BOOL APIENTRY
501VBoxDispDrvBitBlt(SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
502 RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4)
503{
504 BOOL bRc;
505 LOGF_ENTER();
506 STATDRVENTRY(BitBlt, psoTrg);
507
508 LOG(("psoTrg = %p, psoSrc = %p, psoMask = %p, pco = %p, pxlo = %p, prclTrg = %p, pptlSrc = %p, "
509 "pptlMask = %p, pbo = %p, pptlBrush = %p, rop4 = %08X",
510 psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, pptlBrush, rop4));
511
512 bRc = EngBitBlt(getSurfObj(psoTrg), getSurfObj(psoSrc), psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, pptlBrush, rop4);
513 VBVA_OPERATION(psoTrg, BitBlt,
514 (psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, pptlBrush, rop4));
515
516 LOGF_LEAVE();
517 return bRc;
518}
519
520BOOL APIENTRY
521VBoxDispDrvStretchBlt(SURFOBJ *psoDest, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
522 COLORADJUSTMENT *pca, POINTL *pptlHTOrg, RECTL *prclDest, RECTL *prclSrc,
523 POINTL *pptlMask, ULONG iMode)
524{
525 BOOL bRc;
526 LOGF_ENTER();
527 STATDRVENTRY(StretchBlt, psoDest);
528
529 bRc = EngStretchBlt(getSurfObj(psoDest), getSurfObj(psoSrc), psoMask, pco, pxlo, pca, pptlHTOrg,
530 prclDest, prclSrc, pptlMask, iMode);
531 VBVA_OPERATION(psoDest, StretchBlt,
532 (psoDest, psoSrc, psoMask, pco, pxlo, pca, pptlHTOrg, prclDest, prclSrc, pptlMask, iMode));
533
534 LOGF_LEAVE();
535 return bRc;
536}
537
538BOOL APIENTRY
539VBoxDispDrvCopyBits(SURFOBJ *psoDest, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo,
540 RECTL *prclDest, POINTL *pptlSrc)
541{
542 BOOL bRc;
543 RECTL rclDest = *prclDest;
544 POINTL ptlSrc = *pptlSrc;
545 BOOL bDo = TRUE;
546 LOGF_ENTER();
547 STATDRVENTRY(CopyBits, psoDest);
548
549 LOG(("psoDest = %p, psoSrc = %p, pco = %p, pxlo = %p, prclDest = %p, pptlSrc = %p",
550 psoDest, psoSrc, pco, pxlo, prclDest, pptlSrc));
551 DUMPSURF(psoSrc, "psoSrc");
552 DUMPSURF(psoDest, "psoDest");
553 STATPRINT;
554
555#ifdef VBOX_VBVA_ADJUST_RECT
556 /* Experimental fix for too large bitmap updates.
557 *
558 * Some application do a large bitmap update event if only
559 * a small part of the bitmap is actually changed.
560 *
561 * The driver will find the changed rectangle by comparing
562 * the current framebuffer content with the source bitmap.
563 *
564 * The optimization is only active when:
565 * - the VBVA extension is enabled;
566 * - the source bitmap is not cacheable;
567 * - the bitmap formats of both the source and the screen surfaces are equal.
568 *
569 */
570 if ( psoSrc
571 && !VBoxDispIsScreenSurface(psoSrc)
572 && VBoxDispIsScreenSurface(psoDest))
573 {
574 PVBOXDISPDEV pDev = ((PVBOXDISPDEV))psoDest->dhpdev;
575
576 LOG(("offscreen->screen"));
577
578 if ( pDev->vbvaCtx.pVBVA
579 && (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
580 {
581 if ( (psoSrc->fjBitmap & BMF_DONTCACHE) != 0
582 || psoSrc->iUniq == 0)
583 {
584 LOG(("non-cacheable %d->%d (pDev %p)", psoSrc->iBitmapFormat, psoDest->iBitmapFormat, pDev));
585
586 /* It is possible to apply the fix. */
587 bDo = vbvaFindChangedRect(getSurfObj(psoDest), getSurfObj(psoSrc), &rclDest, &ptlSrc);
588 }
589 }
590 }
591
592 if (!bDo)
593 {
594 /* The operation is a NOP. Just return success. */
595 LOGF_LEAVE();
596 return TRUE;
597 }
598#endif /* VBOX_VBVA_ADJUST_RECT */
599
600 bRc = EngCopyBits(getSurfObj(psoDest), getSurfObj(psoSrc), pco, pxlo, &rclDest, &ptlSrc);
601 VBVA_OPERATION(psoDest, CopyBits, (psoDest, psoSrc, pco, pxlo, &rclDest, &ptlSrc));
602
603 LOGF_LEAVE();
604 return bRc;
605}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette