VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine_new/wined3d/query.c@ 48345

Last change on this file since 48345 was 48345, checked in by vboxsync, 11 years ago

header fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.8 KB
Line 
1/*
2 * Copyright 2005 Oliver Stieber
3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21/*
22 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
23 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
24 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
25 * a choice of LGPL license versions is made available with the language indicating
26 * that LGPLv2 or any later version may be used, or where a choice of which version
27 * of the LGPL is applied is otherwise unspecified.
28 */
29
30#include "config.h"
31#include "wine/port.h"
32#include "wined3d_private.h"
33
34WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35
36BOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info)
37{
38 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
39}
40
41void wined3d_event_query_destroy(struct wined3d_event_query *query)
42{
43 if (query->context) context_free_event_query(query);
44 HeapFree(GetProcessHeap(), 0, query);
45}
46
47static enum wined3d_event_query_result wined3d_event_query_test(const struct wined3d_event_query *query,
48 const struct wined3d_device *device)
49{
50 struct wined3d_context *context;
51 const struct wined3d_gl_info *gl_info;
52 enum wined3d_event_query_result ret;
53 BOOL fence_result;
54
55 TRACE("(%p) : device %p\n", query, device);
56
57 if (!query->context)
58 {
59 TRACE("Query not started\n");
60 return WINED3D_EVENT_QUERY_NOT_STARTED;
61 }
62
63#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
64 if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
65 {
66 WARN("Event query tested from wrong thread\n");
67 return WINED3D_EVENT_QUERY_WRONG_THREAD;
68 }
69#endif
70
71 context = context_acquire(device, query->context->current_rt);
72 gl_info = context->gl_info;
73
74 if (gl_info->supported[ARB_SYNC])
75 {
76 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, 0));
77 checkGLcall("glClientWaitSync");
78
79 switch (gl_ret)
80 {
81 case GL_ALREADY_SIGNALED:
82 case GL_CONDITION_SATISFIED:
83 ret = WINED3D_EVENT_QUERY_OK;
84 break;
85
86 case GL_TIMEOUT_EXPIRED:
87 ret = WINED3D_EVENT_QUERY_WAITING;
88 break;
89
90 case GL_WAIT_FAILED:
91 default:
92 ERR("glClientWaitSync returned %#x.\n", gl_ret);
93 ret = WINED3D_EVENT_QUERY_ERROR;
94 }
95 }
96 else if (gl_info->supported[APPLE_FENCE])
97 {
98 fence_result = GL_EXTCALL(glTestFenceAPPLE(query->object.id));
99 checkGLcall("glTestFenceAPPLE");
100 if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
101 else ret = WINED3D_EVENT_QUERY_WAITING;
102 }
103 else if (gl_info->supported[NV_FENCE])
104 {
105 fence_result = GL_EXTCALL(glTestFenceNV(query->object.id));
106 checkGLcall("glTestFenceNV");
107 if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
108 else ret = WINED3D_EVENT_QUERY_WAITING;
109 }
110 else
111 {
112#ifdef VBOX_WITH_WDDM
113 /* doing Flush (rather than Finish) should be enough since we're serialized on the host in any way */
114 gl_info->gl_ops.gl.p_glFlush();
115 ret = WINED3D_EVENT_QUERY_OK;
116#else
117 ERR("Event query created despite lack of GL support\n");
118 ret = WINED3D_EVENT_QUERY_ERROR;
119#endif
120 }
121
122 context_release(context);
123 return ret;
124}
125
126enum wined3d_event_query_result wined3d_event_query_finish(const struct wined3d_event_query *query,
127 const struct wined3d_device *device)
128{
129 struct wined3d_context *context;
130 const struct wined3d_gl_info *gl_info;
131 enum wined3d_event_query_result ret;
132
133 TRACE("(%p)\n", query);
134
135 if (!query->context)
136 {
137 TRACE("Query not started\n");
138 return WINED3D_EVENT_QUERY_NOT_STARTED;
139 }
140 gl_info = query->context->gl_info;
141
142#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
143 if (query->context->tid != GetCurrentThreadId() && !gl_info->supported[ARB_SYNC])
144 {
145 /* A glFinish does not reliably wait for draws in other contexts. The caller has
146 * to find its own way to cope with the thread switch
147 */
148 WARN("Event query finished from wrong thread\n");
149 return WINED3D_EVENT_QUERY_WRONG_THREAD;
150 }
151#endif
152
153 context = context_acquire(device, query->context->current_rt);
154
155 if (gl_info->supported[ARB_SYNC])
156 {
157 /* Apple seems to be into arbitrary limits, and timeouts larger than
158 * 0xfffffffffffffbff immediately return GL_TIMEOUT_EXPIRED. We don't
159 * really care and can live with waiting a few μs less. (OS X 10.7.4). */
160 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0xffff));
161 checkGLcall("glClientWaitSync");
162
163 switch (gl_ret)
164 {
165 case GL_ALREADY_SIGNALED:
166 case GL_CONDITION_SATISFIED:
167 ret = WINED3D_EVENT_QUERY_OK;
168 break;
169
170 /* We don't expect a timeout for a ~584 year wait */
171 default:
172 ERR("glClientWaitSync returned %#x.\n", gl_ret);
173 ret = WINED3D_EVENT_QUERY_ERROR;
174 }
175 }
176 else if (context->gl_info->supported[APPLE_FENCE])
177 {
178 GL_EXTCALL(glFinishFenceAPPLE(query->object.id));
179 checkGLcall("glFinishFenceAPPLE");
180 ret = WINED3D_EVENT_QUERY_OK;
181 }
182 else if (context->gl_info->supported[NV_FENCE])
183 {
184 GL_EXTCALL(glFinishFenceNV(query->object.id));
185 checkGLcall("glFinishFenceNV");
186 ret = WINED3D_EVENT_QUERY_OK;
187 }
188 else
189 {
190 ERR("Event query created without GL support\n");
191 ret = WINED3D_EVENT_QUERY_ERROR;
192 }
193
194 context_release(context);
195 return ret;
196}
197
198void wined3d_event_query_issue(struct wined3d_event_query *query, const struct wined3d_device *device)
199{
200 const struct wined3d_gl_info *gl_info;
201 struct wined3d_context *context;
202
203 if (query->context)
204 {
205#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
206 if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
207 {
208 context_free_event_query(query);
209 context = context_acquire(device, NULL);
210 context_alloc_event_query(context, query);
211 }
212 else
213#endif
214 {
215 context = context_acquire(device, query->context->current_rt);
216 }
217 }
218 else
219 {
220 context = context_acquire(device, NULL);
221 context_alloc_event_query(context, query);
222 }
223
224 gl_info = context->gl_info;
225
226 if (gl_info->supported[ARB_SYNC])
227 {
228 if (query->object.sync) GL_EXTCALL(glDeleteSync(query->object.sync));
229 checkGLcall("glDeleteSync");
230 query->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
231 checkGLcall("glFenceSync");
232 }
233 else if (gl_info->supported[APPLE_FENCE])
234 {
235 GL_EXTCALL(glSetFenceAPPLE(query->object.id));
236 checkGLcall("glSetFenceAPPLE");
237 }
238 else if (gl_info->supported[NV_FENCE])
239 {
240 GL_EXTCALL(glSetFenceNV(query->object.id, GL_ALL_COMPLETED_NV));
241 checkGLcall("glSetFenceNV");
242 }
243
244 context_release(context);
245}
246
247ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
248{
249 ULONG refcount = InterlockedIncrement(&query->ref);
250
251 TRACE("%p increasing refcount to %u.\n", query, refcount);
252
253 return refcount;
254}
255
256ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
257{
258 ULONG refcount = InterlockedDecrement(&query->ref);
259
260 TRACE("%p decreasing refcount to %u.\n", query, refcount);
261
262 if (!refcount)
263 {
264 /* Queries are specific to the GL context that created them. Not
265 * deleting the query will obviously leak it, but that's still better
266 * than potentially deleting a different query with the same id in this
267 * context, and (still) leaking the actual query. */
268 if (query->type == WINED3D_QUERY_TYPE_EVENT)
269 {
270 struct wined3d_event_query *event_query = query->extendedData;
271 if (event_query) wined3d_event_query_destroy(event_query);
272 }
273 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
274 {
275 struct wined3d_occlusion_query *oq = query->extendedData;
276
277 if (oq->context) context_free_occlusion_query(oq);
278 HeapFree(GetProcessHeap(), 0, query->extendedData);
279 }
280
281 HeapFree(GetProcessHeap(), 0, query);
282 }
283
284 return refcount;
285}
286
287HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
288 void *data, UINT data_size, DWORD flags)
289{
290 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
291 query, data, data_size, flags);
292
293 return query->query_ops->query_get_data(query, data, data_size, flags);
294}
295
296UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
297{
298 TRACE("query %p.\n", query);
299
300 return query->data_size;
301}
302
303HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
304{
305 TRACE("query %p, flags %#x.\n", query, flags);
306
307 return query->query_ops->query_issue(query, flags);
308}
309
310static HRESULT wined3d_occlusion_query_ops_get_data(struct wined3d_query *query,
311 void *pData, DWORD dwSize, DWORD flags)
312{
313 struct wined3d_occlusion_query *oq = query->extendedData;
314 struct wined3d_device *device = query->device;
315 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
316 struct wined3d_context *context;
317 DWORD* data = pData;
318 GLuint available;
319 GLuint samples;
320 HRESULT res;
321
322 TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, flags %#x.\n", query, pData, dwSize, flags);
323
324 if (!oq->context)
325 query->state = QUERY_CREATED;
326
327 if (query->state == QUERY_CREATED)
328 {
329 /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
330 TRACE("Query wasn't yet started, returning S_OK\n");
331 if(data) *data = 0;
332 return S_OK;
333 }
334
335 if (query->state == QUERY_BUILDING)
336 {
337 /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
338 TRACE("Query is building, returning S_FALSE\n");
339 return S_FALSE;
340 }
341
342 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
343 {
344 WARN("%p Occlusion queries not supported. Returning 1.\n", query);
345 *data = 1;
346 return S_OK;
347 }
348
349#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
350 if (oq->context->tid != GetCurrentThreadId())
351 {
352 FIXME("%p Wrong thread, returning 1.\n", query);
353 *data = 1;
354 return S_OK;
355 }
356#endif
357
358 context = context_acquire(query->device, oq->context->current_rt);
359
360 GL_EXTCALL(glGetQueryObjectuivARB(oq->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
361 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
362 TRACE("available %#x.\n", available);
363
364 if (available)
365 {
366 if (data)
367 {
368 GL_EXTCALL(glGetQueryObjectuivARB(oq->id, GL_QUERY_RESULT_ARB, &samples));
369 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
370 TRACE("Returning %d samples.\n", samples);
371 *data = samples;
372 }
373 res = S_OK;
374 }
375 else
376 {
377 res = S_FALSE;
378 }
379
380 context_release(context);
381
382 return res;
383}
384
385static HRESULT wined3d_event_query_ops_get_data(struct wined3d_query *query,
386 void *pData, DWORD dwSize, DWORD flags)
387{
388 struct wined3d_event_query *event_query = query->extendedData;
389 BOOL *data = pData;
390 enum wined3d_event_query_result ret;
391
392 TRACE("query %p, pData %p, dwSize %#x, flags %#x.\n", query, pData, dwSize, flags);
393
394 if (!pData || !dwSize) return S_OK;
395 if (!event_query)
396 {
397 WARN("Event query not supported by GL, reporting GPU idle.\n");
398 *data = TRUE;
399 return S_OK;
400 }
401
402 ret = wined3d_event_query_test(event_query, query->device);
403 switch(ret)
404 {
405 case WINED3D_EVENT_QUERY_OK:
406 case WINED3D_EVENT_QUERY_NOT_STARTED:
407 *data = TRUE;
408 break;
409
410 case WINED3D_EVENT_QUERY_WAITING:
411 *data = FALSE;
412 break;
413
414 case WINED3D_EVENT_QUERY_WRONG_THREAD:
415 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
416 *data = TRUE;
417 break;
418
419 case WINED3D_EVENT_QUERY_ERROR:
420 ERR("The GL event query failed, returning D3DERR_INVALIDCALL\n");
421 return WINED3DERR_INVALIDCALL;
422 }
423
424 return S_OK;
425}
426
427enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
428{
429 TRACE("query %p.\n", query);
430
431 return query->type;
432}
433
434static HRESULT wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
435{
436 TRACE("query %p, flags %#x.\n", query, flags);
437
438 TRACE("(%p) : flags %#x, type D3DQUERY_EVENT\n", query, flags);
439 if (flags & WINED3DISSUE_END)
440 {
441 struct wined3d_event_query *event_query = query->extendedData;
442
443 /* Faked event query support */
444 if (!event_query) return WINED3D_OK;
445
446 wined3d_event_query_issue(event_query, query->device);
447 }
448 else if (flags & WINED3DISSUE_BEGIN)
449 {
450 /* Started implicitly at device creation */
451 ERR("Event query issued with START flag - what to do?\n");
452 }
453
454 if (flags & WINED3DISSUE_BEGIN)
455 query->state = QUERY_BUILDING;
456 else
457 query->state = QUERY_SIGNALLED;
458
459 return WINED3D_OK;
460}
461
462static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
463{
464 struct wined3d_device *device = query->device;
465 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
466
467 TRACE("query %p, flags %#x.\n", query, flags);
468
469 if (gl_info->supported[ARB_OCCLUSION_QUERY])
470 {
471 struct wined3d_occlusion_query *oq = query->extendedData;
472 struct wined3d_context *context;
473
474 /* This is allowed according to msdn and our tests. Reset the query and restart */
475 if (flags & WINED3DISSUE_BEGIN)
476 {
477 if (query->state == QUERY_BUILDING)
478 {
479#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
480 if (oq->context->tid != GetCurrentThreadId())
481 {
482 FIXME("Wrong thread, can't restart query.\n");
483
484 context_free_occlusion_query(oq);
485 context = context_acquire(query->device, NULL);
486 context_alloc_occlusion_query(context, oq);
487 }
488 else
489#endif
490 {
491 context = context_acquire(query->device, oq->context->current_rt);
492
493 GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
494 checkGLcall("glEndQuery()");
495 }
496 }
497 else
498 {
499 if (oq->context) context_free_occlusion_query(oq);
500 context = context_acquire(query->device, NULL);
501 context_alloc_occlusion_query(context, oq);
502 }
503
504 GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, oq->id));
505 checkGLcall("glBeginQuery()");
506
507 context_release(context);
508 }
509 if (flags & WINED3DISSUE_END)
510 {
511 /* Msdn says _END on a non-building occlusion query returns an error, but
512 * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
513 * generating an error
514 */
515 if (query->state == QUERY_BUILDING)
516 {
517#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
518 if (oq->context->tid != GetCurrentThreadId())
519 {
520 FIXME("Wrong thread, can't end query.\n");
521 }
522 else
523#endif
524 {
525 context = context_acquire(query->device, oq->context->current_rt);
526
527 GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
528 checkGLcall("glEndQuery()");
529
530 context_release(context);
531 }
532 }
533 }
534 }
535 else
536 {
537 FIXME("%p Occlusion queries not supported.\n", query);
538 }
539
540 if (flags & WINED3DISSUE_BEGIN)
541 query->state = QUERY_BUILDING;
542 else
543 query->state = QUERY_SIGNALLED;
544
545 return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */
546}
547
548static const struct wined3d_query_ops event_query_ops =
549{
550 wined3d_event_query_ops_get_data,
551 wined3d_event_query_ops_issue,
552};
553
554static const struct wined3d_query_ops occlusion_query_ops =
555{
556 wined3d_occlusion_query_ops_get_data,
557 wined3d_occlusion_query_ops_issue,
558};
559
560static HRESULT query_init(struct wined3d_query *query, struct wined3d_device *device, enum wined3d_query_type type)
561{
562 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
563
564 switch (type)
565 {
566 case WINED3D_QUERY_TYPE_OCCLUSION:
567 TRACE("Occlusion query.\n");
568 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
569 {
570 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
571 return WINED3DERR_NOTAVAILABLE;
572 }
573 query->query_ops = &occlusion_query_ops;
574 query->data_size = sizeof(DWORD);
575 query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
576 if (!query->extendedData)
577 {
578 ERR("Failed to allocate occlusion query extended data.\n");
579 return E_OUTOFMEMORY;
580 }
581 ((struct wined3d_occlusion_query *)query->extendedData)->context = NULL;
582 break;
583
584 case WINED3D_QUERY_TYPE_EVENT:
585 TRACE("Event query.\n");
586 if (!wined3d_event_query_supported(gl_info))
587 {
588 /* Half-Life 2 needs this query. It does not render the main
589 * menu correctly otherwise. Pretend to support it, faking
590 * this query does not do much harm except potentially
591 * lowering performance. */
592 FIXME("Event query: Unimplemented, but pretending to be supported.\n");
593 }
594 query->query_ops = &event_query_ops;
595 query->data_size = sizeof(BOOL);
596 query->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_event_query));
597 if (!query->extendedData)
598 {
599 ERR("Failed to allocate event query memory.\n");
600 return E_OUTOFMEMORY;
601 }
602 break;
603
604 case WINED3D_QUERY_TYPE_VCACHE:
605 case WINED3D_QUERY_TYPE_RESOURCE_MANAGER:
606 case WINED3D_QUERY_TYPE_VERTEX_STATS:
607 case WINED3D_QUERY_TYPE_TIMESTAMP:
608 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
609 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
610 case WINED3D_QUERY_TYPE_PIPELINE_TIMINGS:
611 case WINED3D_QUERY_TYPE_INTERFACE_TIMINGS:
612 case WINED3D_QUERY_TYPE_VERTEX_TIMINGS:
613 case WINED3D_QUERY_TYPE_PIXEL_TIMINGS:
614 case WINED3D_QUERY_TYPE_BANDWIDTH_TIMINGS:
615 case WINED3D_QUERY_TYPE_CACHE_UTILIZATION:
616 default:
617 FIXME("Unhandled query type %#x.\n", type);
618 return WINED3DERR_NOTAVAILABLE;
619 }
620
621 query->type = type;
622 query->state = QUERY_CREATED;
623 query->device = device;
624 query->ref = 1;
625
626 return WINED3D_OK;
627}
628
629HRESULT CDECL wined3d_query_create(struct wined3d_device *device,
630 enum wined3d_query_type type, struct wined3d_query **query)
631{
632 struct wined3d_query *object;
633 HRESULT hr;
634
635 TRACE("device %p, type %#x, query %p.\n", device, type, query);
636
637 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
638 if (!object)
639 return E_OUTOFMEMORY;
640
641 hr = query_init(object, device, type);
642 if (FAILED(hr))
643 {
644 WARN("Failed to initialize query, hr %#x.\n", hr);
645 HeapFree(GetProcessHeap(), 0, object);
646 return hr;
647 }
648
649 TRACE("Created query %p.\n", object);
650 *query = object;
651
652 return WINED3D_OK;
653}
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