1 /* 2 ** Copyright 2011, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.glesv2debugger; 18 19 import com.android.glesv2debugger.DebuggerMessage.Message; 20 import com.android.glesv2debugger.DebuggerMessage.Message.Function; 21 import com.android.glesv2debugger.DebuggerMessage.Message.Prop; 22 import com.android.glesv2debugger.DebuggerMessage.Message.Type; 23 import com.android.sdklib.util.SparseArray; 24 25 import org.eclipse.jface.action.Action; 26 import org.eclipse.jface.action.IMenuListener; 27 import org.eclipse.jface.action.IMenuManager; 28 import org.eclipse.jface.action.IToolBarManager; 29 import org.eclipse.jface.action.MenuManager; 30 import org.eclipse.jface.action.Separator; 31 import org.eclipse.jface.dialogs.InputDialog; 32 import org.eclipse.jface.dialogs.MessageDialog; 33 import org.eclipse.jface.viewers.ISelectionChangedListener; 34 import org.eclipse.jface.viewers.IStructuredContentProvider; 35 import org.eclipse.jface.viewers.ITableLabelProvider; 36 import org.eclipse.jface.viewers.LabelProvider; 37 import org.eclipse.jface.viewers.ListViewer; 38 import org.eclipse.jface.viewers.SelectionChangedEvent; 39 import org.eclipse.jface.viewers.StructuredSelection; 40 import org.eclipse.jface.viewers.TreeViewer; 41 import org.eclipse.jface.viewers.Viewer; 42 import org.eclipse.jface.viewers.ViewerFilter; 43 import org.eclipse.jface.viewers.ViewerSorter; 44 import org.eclipse.jface.window.Window; 45 import org.eclipse.swt.SWT; 46 import org.eclipse.swt.events.SelectionEvent; 47 import org.eclipse.swt.events.SelectionListener; 48 import org.eclipse.swt.graphics.Font; 49 import org.eclipse.swt.graphics.GC; 50 import org.eclipse.swt.graphics.Image; 51 import org.eclipse.swt.graphics.Point; 52 import org.eclipse.swt.graphics.Rectangle; 53 import org.eclipse.swt.layout.GridData; 54 import org.eclipse.swt.layout.GridLayout; 55 import org.eclipse.swt.widgets.Canvas; 56 import org.eclipse.swt.widgets.Composite; 57 import org.eclipse.swt.widgets.Event; 58 import org.eclipse.swt.widgets.FileDialog; 59 import org.eclipse.swt.widgets.Listener; 60 import org.eclipse.swt.widgets.Menu; 61 import org.eclipse.swt.widgets.ScrollBar; 62 import org.eclipse.swt.widgets.Shell; 63 import org.eclipse.swt.widgets.Slider; 64 import org.eclipse.swt.widgets.TabFolder; 65 import org.eclipse.swt.widgets.TabItem; 66 import org.eclipse.swt.widgets.Text; 67 import org.eclipse.ui.IActionBars; 68 import org.eclipse.ui.IWorkbenchActionConstants; 69 import org.eclipse.ui.PlatformUI; 70 import org.eclipse.ui.part.ViewPart; 71 72 import java.io.FileInputStream; 73 import java.io.FileNotFoundException; 74 import java.nio.ByteOrder; 75 76 /** 77 * This sample class demonstrates how to plug-in a new workbench view. The view 78 * shows data obtained from the model. The sample creates a dummy model on the 79 * fly, but a real implementation would connect to the model available either in 80 * this or another plug-in (e.g. the workspace). The view is connected to the 81 * model using a content provider. 82 * <p> 83 * The view uses a label provider to define how model objects should be 84 * presented in the view. Each view can present the same model objects using 85 * different labels and icons, if needed. Alternatively, a single label provider 86 * can be shared between views in order to ensure that objects of the same type 87 * are presented in the same way everywhere. 88 * <p> 89 */ 90 91 public class SampleView extends ViewPart implements Runnable, SelectionListener { 92 public static final ByteOrder targetByteOrder = ByteOrder.LITTLE_ENDIAN; 93 94 boolean running = false; 95 Thread thread; 96 MessageQueue messageQueue; 97 SparseArray<DebugContext> debugContexts = new SparseArray<DebugContext>(); 98 99 /** The ID of the view as specified by the extension. */ 100 public static final String ID = "glesv2debuggerclient.views.SampleView"; 101 102 TabFolder tabFolder; 103 TabItem tabItemText, tabItemImage, tabItemBreakpointOption; 104 TabItem tabItemShaderEditor, tabContextViewer; 105 ListViewer viewer; // ListViewer / TableViewer 106 Slider frameNum; // scale max cannot overlap min, so max is array size 107 TreeViewer contextViewer; 108 BreakpointOption breakpointOption; 109 ShaderEditor shaderEditor; 110 Canvas canvas; 111 Text text; 112 Action actionConnect; // connect / disconnect 113 114 Action actionAutoScroll; 115 Action actionFilter; 116 Action actionPort; 117 118 Action actContext; // for toggling contexts 119 DebugContext current = null; 120 121 Point origin = new Point(0, 0); // for smooth scrolling canvas 122 String[] filters = null; 123 124 class ViewContentProvider extends LabelProvider implements IStructuredContentProvider, 125 ITableLabelProvider { 126 Frame frame = null; 127 128 @Override inputChanged(Viewer v, Object oldInput, Object newInput)129 public void inputChanged(Viewer v, Object oldInput, Object newInput) { 130 frame = (Frame) newInput; 131 } 132 133 @Override dispose()134 public void dispose() { 135 } 136 137 @Override getElements(Object parent)138 public Object[] getElements(Object parent) { 139 return frame.get().toArray(); 140 } 141 142 @Override getText(Object obj)143 public String getText(Object obj) { 144 MessageData msgData = (MessageData) obj; 145 return msgData.text; 146 } 147 148 @Override getImage(Object obj)149 public Image getImage(Object obj) { 150 MessageData msgData = (MessageData) obj; 151 return msgData.getImage(); 152 } 153 154 @Override getColumnText(Object obj, int index)155 public String getColumnText(Object obj, int index) { 156 MessageData msgData = (MessageData) obj; 157 if (index >= msgData.columns.length) 158 return null; 159 return msgData.columns[index]; 160 } 161 162 @Override getColumnImage(Object obj, int index)163 public Image getColumnImage(Object obj, int index) { 164 if (index > -1) 165 return null; 166 MessageData msgData = (MessageData) obj; 167 return msgData.getImage(); 168 } 169 } 170 171 class NameSorter extends ViewerSorter { 172 @Override compare(Viewer viewer, Object e1, Object e2)173 public int compare(Viewer viewer, Object e1, Object e2) { 174 MessageData m1 = (MessageData) e1; 175 MessageData m2 = (MessageData) e2; 176 return (int) ((m1.msg.getTime() - m2.msg.getTime()) * 100); 177 } 178 } 179 180 class Filter extends ViewerFilter { 181 @Override select(Viewer viewer, Object parentElement, Object element)182 public boolean select(Viewer viewer, Object parentElement, 183 Object element) { 184 MessageData msgData = (MessageData) element; 185 if (null == filters) 186 return true; 187 for (int i = 0; i < filters.length; i++) 188 if (msgData.text.contains(filters[i])) 189 return true; 190 return false; 191 } 192 } 193 SampleView()194 public SampleView() { 195 196 } 197 createLeftPane(Composite parent)198 public void createLeftPane(Composite parent) { 199 Composite composite = new Composite(parent, 0); 200 201 GridLayout gridLayout = new GridLayout(); 202 gridLayout.numColumns = 1; 203 composite.setLayout(gridLayout); 204 205 frameNum = new Slider(composite, SWT.BORDER | SWT.HORIZONTAL); 206 frameNum.setMinimum(0); 207 frameNum.setMaximum(1); 208 frameNum.setSelection(0); 209 frameNum.addSelectionListener(this); 210 211 GridData gridData = new GridData(); 212 gridData.horizontalAlignment = SWT.FILL; 213 gridData.grabExcessHorizontalSpace = true; 214 gridData.verticalAlignment = SWT.FILL; 215 frameNum.setLayoutData(gridData); 216 217 // Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL | 218 // SWT.MULTI 219 // | SWT.FULL_SELECTION); 220 // TableLayout layout = new TableLayout(); 221 // table.setLayout(layout); 222 // table.setLinesVisible(true); 223 // table.setHeaderVisible(true); 224 // String[] headings = { 225 // "Name", "Elapsed (ms)", "Detail" 226 // }; 227 // int[] weights = { 228 // 50, 16, 60 229 // }; 230 // int[] widths = { 231 // 180, 90, 200 232 // }; 233 // for (int i = 0; i < headings.length; i++) { 234 // layout.addColumnData(new ColumnWeightData(weights[i], widths[i], 235 // true)); 236 // TableColumn nameCol = new TableColumn(table, SWT.NONE, i); 237 // nameCol.setText(headings[i]); 238 // } 239 240 // viewer = new TableViewer(table); 241 viewer = new ListViewer(composite, SWT.DEFAULT); 242 viewer.getList().setFont(new Font(viewer.getList().getDisplay(), 243 "Courier", 10, SWT.BOLD)); 244 ViewContentProvider contentProvider = new ViewContentProvider(); 245 viewer.setContentProvider(contentProvider); 246 viewer.setLabelProvider(contentProvider); 247 // viewer.setSorter(new NameSorter()); 248 viewer.setFilters(new ViewerFilter[] { 249 new Filter() 250 }); 251 252 gridData = new GridData(); 253 gridData.horizontalAlignment = SWT.FILL; 254 gridData.grabExcessHorizontalSpace = true; 255 gridData.verticalAlignment = SWT.FILL; 256 gridData.grabExcessVerticalSpace = true; 257 viewer.getControl().setLayoutData(gridData); 258 } 259 260 /** 261 * This is a callback that will allow us to create the viewer and initialize 262 * it. 263 */ 264 @Override createPartControl(Composite parent)265 public void createPartControl(Composite parent) { 266 createLeftPane(parent); 267 268 // Create the help context id for the viewer's control 269 PlatformUI.getWorkbench().getHelpSystem() 270 .setHelp(viewer.getControl(), "GLESv2DebuggerClient.viewer"); 271 272 tabFolder = new TabFolder(parent, SWT.BORDER); 273 274 text = new Text(tabFolder, SWT.NO_BACKGROUND | SWT.READ_ONLY 275 | SWT.V_SCROLL | SWT.H_SCROLL); 276 277 tabItemText = new TabItem(tabFolder, SWT.NONE); 278 tabItemText.setText("Text"); 279 tabItemText.setControl(text); 280 281 canvas = new Canvas(tabFolder, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE 282 | SWT.V_SCROLL | SWT.H_SCROLL); 283 tabItemImage = new TabItem(tabFolder, SWT.NONE); 284 tabItemImage.setText("Image"); 285 tabItemImage.setControl(canvas); 286 287 breakpointOption = new BreakpointOption(this, tabFolder); 288 tabItemBreakpointOption = new TabItem(tabFolder, SWT.NONE); 289 tabItemBreakpointOption.setText("Breakpoint Option"); 290 tabItemBreakpointOption.setControl(breakpointOption); 291 292 shaderEditor = new ShaderEditor(this, tabFolder); 293 tabItemShaderEditor = new TabItem(tabFolder, SWT.NONE); 294 tabItemShaderEditor.setText("Shader Editor"); 295 tabItemShaderEditor.setControl(shaderEditor); 296 297 contextViewer = new TreeViewer(tabFolder); 298 ContextViewProvider contextViewProvider = new ContextViewProvider(this); 299 contextViewer.addSelectionChangedListener(contextViewProvider); 300 contextViewer.setContentProvider(contextViewProvider); 301 contextViewer.setLabelProvider(contextViewProvider); 302 tabContextViewer = new TabItem(tabFolder, SWT.NONE); 303 tabContextViewer.setText("Context Viewer"); 304 tabContextViewer.setControl(contextViewer.getTree()); 305 306 final ScrollBar hBar = canvas.getHorizontalBar(); 307 hBar.addListener(SWT.Selection, new Listener() { 308 @Override 309 public void handleEvent(Event e) { 310 if (null == canvas.getBackgroundImage()) 311 return; 312 Image image = canvas.getBackgroundImage(); 313 int hSelection = hBar.getSelection(); 314 int destX = -hSelection - origin.x; 315 Rectangle rect = image.getBounds(); 316 canvas.scroll(destX, 0, 0, 0, rect.width, rect.height, false); 317 origin.x = -hSelection; 318 } 319 }); 320 final ScrollBar vBar = canvas.getVerticalBar(); 321 vBar.addListener(SWT.Selection, new Listener() { 322 @Override 323 public void handleEvent(Event e) { 324 if (null == canvas.getBackgroundImage()) 325 return; 326 Image image = canvas.getBackgroundImage(); 327 int vSelection = vBar.getSelection(); 328 int destY = -vSelection - origin.y; 329 Rectangle rect = image.getBounds(); 330 canvas.scroll(0, destY, 0, 0, rect.width, rect.height, false); 331 origin.y = -vSelection; 332 } 333 }); 334 canvas.addListener(SWT.Resize, new Listener() { 335 @Override 336 public void handleEvent(Event e) { 337 if (null == canvas.getBackgroundImage()) 338 return; 339 Image image = canvas.getBackgroundImage(); 340 Rectangle rect = image.getBounds(); 341 Rectangle client = canvas.getClientArea(); 342 hBar.setMaximum(rect.width); 343 vBar.setMaximum(rect.height); 344 hBar.setThumb(Math.min(rect.width, client.width)); 345 vBar.setThumb(Math.min(rect.height, client.height)); 346 int hPage = rect.width - client.width; 347 int vPage = rect.height - client.height; 348 int hSelection = hBar.getSelection(); 349 int vSelection = vBar.getSelection(); 350 if (hSelection >= hPage) { 351 if (hPage <= 0) 352 hSelection = 0; 353 origin.x = -hSelection; 354 } 355 if (vSelection >= vPage) { 356 if (vPage <= 0) 357 vSelection = 0; 358 origin.y = -vSelection; 359 } 360 canvas.redraw(); 361 } 362 }); 363 canvas.addListener(SWT.Paint, new Listener() { 364 @Override 365 public void handleEvent(Event e) { 366 if (null == canvas.getBackgroundImage()) 367 return; 368 Image image = canvas.getBackgroundImage(); 369 GC gc = e.gc; 370 gc.drawImage(image, origin.x, origin.y); 371 Rectangle rect = image.getBounds(); 372 Rectangle client = canvas.getClientArea(); 373 int marginWidth = client.width - rect.width; 374 if (marginWidth > 0) { 375 gc.fillRectangle(rect.width, 0, marginWidth, client.height); 376 } 377 int marginHeight = client.height - rect.height; 378 if (marginHeight > 0) { 379 gc.fillRectangle(0, rect.height, client.width, marginHeight); 380 } 381 } 382 }); 383 384 hookContextMenu(); 385 hookSelectionChanged(); 386 contributeToActionBars(); 387 388 messageQueue = new MessageQueue(this, new ProcessMessage[] { 389 breakpointOption, shaderEditor 390 }); 391 } 392 hookContextMenu()393 private void hookContextMenu() { 394 MenuManager menuMgr = new MenuManager("#PopupMenu"); 395 menuMgr.setRemoveAllWhenShown(true); 396 menuMgr.addMenuListener(new IMenuListener() { 397 @Override 398 public void menuAboutToShow(IMenuManager manager) { 399 SampleView.this.fillContextMenu(manager); 400 } 401 }); 402 Menu menu = menuMgr.createContextMenu(viewer.getControl()); 403 viewer.getControl().setMenu(menu); 404 getSite().registerContextMenu(menuMgr, viewer); 405 } 406 contributeToActionBars()407 private void contributeToActionBars() { 408 IActionBars bars = getViewSite().getActionBars(); 409 fillLocalPullDown(bars.getMenuManager()); 410 fillLocalToolBar(bars.getToolBarManager()); 411 } 412 fillLocalPullDown(IMenuManager manager)413 private void fillLocalPullDown(IMenuManager manager) { 414 // manager.add(actionConnect); 415 // manager.add(new Separator()); 416 // manager.add(actionDisconnect); 417 } 418 fillContextMenu(IMenuManager manager)419 private void fillContextMenu(IMenuManager manager) { 420 // manager.add(actionConnect); 421 // manager.add(actionDisconnect); 422 // Other plug-ins can contribute there actions here 423 manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); 424 } 425 fillLocalToolBar(final IToolBarManager manager)426 private void fillLocalToolBar(final IToolBarManager manager) { 427 actionConnect = new Action("Connect", Action.AS_PUSH_BUTTON) { 428 @Override 429 public void run() { 430 if (!running) 431 changeContext(null); // viewer will switch to newest context 432 connectDisconnect(); 433 } 434 }; 435 manager.add(actionConnect); 436 437 manager.add(new Action("Open File", Action.AS_PUSH_BUTTON) 438 { 439 @Override 440 public void run() 441 { 442 if (!running) 443 { 444 changeContext(null); // viewer will switch to newest context 445 openFile(); 446 } 447 } 448 }); 449 450 final Shell shell = this.getViewSite().getShell(); 451 actionAutoScroll = new Action("Auto Scroll", Action.AS_CHECK_BOX) { 452 @Override 453 public void run() { 454 } 455 }; 456 actionAutoScroll.setChecked(true); 457 manager.add(actionAutoScroll); 458 459 actionFilter = new Action("*", Action.AS_DROP_DOWN_MENU) { 460 @Override 461 public void run() { 462 org.eclipse.jface.dialogs.InputDialog dialog = new org.eclipse.jface.dialogs.InputDialog( 463 shell, "Contains Filter", 464 "case sensitive substring or *", 465 actionFilter.getText(), null); 466 if (Window.OK == dialog.open()) { 467 actionFilter.setText(dialog.getValue()); 468 manager.update(true); 469 filters = dialog.getValue().split("\\|"); 470 if (filters.length == 1 && filters[0].equals("*")) 471 filters = null; 472 viewer.refresh(); 473 } 474 475 } 476 }; 477 manager.add(actionFilter); 478 479 manager.add(new Action("CaptureDraw", Action.AS_DROP_DOWN_MENU) 480 { 481 @Override 482 public void run() 483 { 484 int contextId = 0; 485 if (current != null) 486 contextId = current.contextId; 487 InputDialog inputDialog = new InputDialog(shell, 488 "Capture glDrawArrays/Elements", 489 "Enter number of glDrawArrays/Elements to glReadPixels for " 490 + "context 0x" + Integer.toHexString(contextId) + 491 "\n(0x0 is any context)", "9001", null); 492 if (inputDialog.open() != Window.OK) 493 return; 494 Message.Builder builder = Message.newBuilder(); 495 builder.setContextId(contextId); 496 builder.setType(Type.Response); 497 builder.setExpectResponse(false); 498 builder.setFunction(Function.SETPROP); 499 builder.setProp(Prop.CaptureDraw); 500 builder.setArg0(Integer.parseInt(inputDialog.getValue())); 501 messageQueue.addCommand(builder.build()); 502 } 503 }); 504 505 manager.add(new Action("CaptureSwap", Action.AS_DROP_DOWN_MENU) 506 { 507 @Override 508 public void run() 509 { 510 int contextId = 0; 511 if (current != null) 512 contextId = current.contextId; 513 InputDialog inputDialog = new InputDialog(shell, 514 "Capture eglSwapBuffers", 515 "Enter number of eglSwapBuffers to glReadPixels for " 516 + "context 0x" + Integer.toHexString(contextId) + 517 "\n(0x0 is any context)", "9001", null); 518 if (inputDialog.open() != Window.OK) 519 return; 520 Message.Builder builder = Message.newBuilder(); 521 builder.setContextId(contextId); 522 builder.setType(Type.Response); 523 builder.setExpectResponse(false); 524 builder.setFunction(Function.SETPROP); 525 builder.setProp(Prop.CaptureSwap); 526 builder.setArg0(Integer.parseInt(inputDialog.getValue())); 527 messageQueue.addCommand(builder.build()); 528 } 529 }); 530 531 manager.add(new Action("SYSTEM_TIME_THREAD", Action.AS_DROP_DOWN_MENU) 532 { 533 @Override 534 public void run() 535 { 536 final String[] timeModes = { 537 "SYSTEM_TIME_REALTIME", "SYSTEM_TIME_MONOTONIC", "SYSTEM_TIME_PROCESS", 538 "SYSTEM_TIME_THREAD" 539 }; 540 int i = java.util.Arrays.asList(timeModes).indexOf(this.getText()); 541 i = (i + 1) % timeModes.length; 542 Message.Builder builder = Message.newBuilder(); 543 builder.setContextId(0); // FIXME: proper context id 544 builder.setType(Type.Response); 545 builder.setExpectResponse(false); 546 builder.setFunction(Message.Function.SETPROP); 547 builder.setProp(Prop.TimeMode); 548 builder.setArg0(i); 549 messageQueue.addCommand(builder.build()); 550 this.setText(timeModes[i]); 551 manager.update(true); 552 } 553 }); 554 555 actContext = new Action("Context: 0x", Action.AS_DROP_DOWN_MENU) { 556 @Override 557 public void run() { 558 if (debugContexts.size() < 2) 559 return; 560 final String idStr = this.getText().substring( 561 "Context: 0x".length()); 562 if (idStr.length() == 0) 563 return; 564 final int contextId = Integer.parseInt(idStr, 16); 565 int index = debugContexts.indexOfKey(contextId); 566 index = (index + 1) % debugContexts.size(); 567 changeContext(debugContexts.valueAt(index)); 568 } 569 }; 570 manager.add(actContext); 571 572 actionPort = new Action("5039", Action.AS_DROP_DOWN_MENU) 573 { 574 @Override 575 public void run() { 576 InputDialog dialog = new InputDialog(shell, "Port", "Debugger port", 577 actionPort.getText(), null); 578 if (Window.OK == dialog.open()) { 579 actionPort.setText(dialog.getValue()); 580 manager.update(true); 581 } 582 } 583 }; 584 manager.add(actionPort); 585 586 manager.add(new Action("CodeGen Frame", Action.AS_PUSH_BUTTON) 587 { 588 @Override 589 public void run() 590 { 591 if (current != null) 592 { 593 new CodeGen().codeGenFrame((Frame) viewer.getInput()); 594 // need to reload current frame 595 viewer.setInput(current.getFrame(frameNum.getSelection())); 596 } 597 } 598 }); 599 600 manager.add(new Action("CodeGen Frames", Action.AS_PUSH_BUTTON) 601 { 602 @Override 603 public void run() 604 { 605 if (current != null) 606 { 607 new CodeGen().codeGenFrames(current, frameNum.getSelection() + 1, 608 getSite().getShell()); 609 // need to reload current frame 610 viewer.setInput(current.getFrame(frameNum.getSelection())); 611 } 612 } 613 }); 614 } 615 openFile()616 private void openFile() { 617 FileDialog dialog = new FileDialog(getSite().getShell(), SWT.OPEN); 618 dialog.setText("Open"); 619 dialog.setFilterExtensions(new String[] { 620 "*.gles2dbg" 621 }); 622 String filePath = dialog.open(); 623 if (filePath == null) 624 return; 625 FileInputStream file = null; 626 try { 627 file = new FileInputStream(filePath); 628 } catch (FileNotFoundException e) { 629 e.printStackTrace(); 630 return; 631 } 632 running = true; 633 messageQueue.start(targetByteOrder, file); 634 thread = new Thread(this); 635 thread.start(); 636 actionConnect.setText("Disconnect"); 637 getViewSite().getActionBars().getToolBarManager().update(true); 638 } 639 connectDisconnect()640 private void connectDisconnect() { 641 if (!running) { 642 running = true; 643 messageQueue.start(targetByteOrder, null); 644 thread = new Thread(this); 645 thread.start(); 646 actionConnect.setText("Disconnect"); 647 } else { 648 running = false; 649 messageQueue.stop(); 650 actionConnect.setText("Connect"); 651 } 652 this.getSite().getShell().getDisplay().syncExec(new Runnable() { 653 @Override 654 public void run() { 655 getViewSite().getActionBars().getToolBarManager().update(true); 656 } 657 }); 658 } 659 messageDataSelected(final MessageData msgData)660 void messageDataSelected(final MessageData msgData) { 661 if (null == msgData) 662 return; 663 if (frameNum.getSelection() == frameNum.getMaximum()) 664 return; // scale max cannot overlap min, so max is array size 665 final Frame frame = current.getFrame(frameNum.getSelection()); 666 final Context context = frame.computeContext(msgData); 667 contextViewer.setInput(context); 668 if (msgData.getImage() != null) { 669 canvas.setBackgroundImage(msgData.getImage()); 670 tabFolder.setSelection(tabItemImage); 671 canvas.redraw(); 672 } else if (null != msgData.shader) { 673 text.setText(msgData.shader); 674 tabFolder.setSelection(tabItemText); 675 } else if (null != msgData.attribs) { 676 StringBuilder builder = new StringBuilder(); 677 final int maxAttrib = msgData.msg.getArg7(); 678 for (int i = 0; i < msgData.attribs[0].length / 4; i++) { 679 if (msgData.indices != null) { 680 builder.append(msgData.indices[i] & 0xffff); 681 builder.append(": "); 682 } 683 for (int j = 0; j < maxAttrib; j++) { 684 for (int k = 0; k < 4; k++) 685 builder.append(String.format("%.3g ", msgData.attribs[j][i * 4 + k])); 686 if (j < maxAttrib - 1) 687 builder.append("|| "); 688 } 689 builder.append('\n'); 690 } 691 text.setText(builder.toString()); 692 tabFolder.setSelection(tabItemText); 693 } 694 } 695 hookSelectionChanged()696 private void hookSelectionChanged() { 697 viewer.addSelectionChangedListener(new ISelectionChangedListener() { 698 @Override 699 public void selectionChanged(SelectionChangedEvent event) { 700 StructuredSelection selection = (StructuredSelection) event 701 .getSelection(); 702 if (null == selection) 703 return; 704 MessageData msgData = (MessageData) selection.getFirstElement(); 705 messageDataSelected(msgData); 706 } 707 }); 708 } 709 showError(final Exception e)710 public void showError(final Exception e) { 711 viewer.getControl().getDisplay().syncExec(new Runnable() { 712 @Override 713 public void run() { 714 MessageDialog.openError(viewer.getControl().getShell(), 715 "GL ES 2.0 Debugger Client", e.getMessage()); 716 } 717 }); 718 } 719 720 /** 721 * Passing the focus request to the viewer's control. 722 */ 723 @Override setFocus()724 public void setFocus() { 725 viewer.getControl().setFocus(); 726 } 727 728 @Override run()729 public void run() { 730 int newMessages = 0; 731 732 boolean shaderEditorUpdate = false; 733 while (running) { 734 final Message oriMsg = messageQueue.removeCompleteMessage(0); 735 if (oriMsg == null && !messageQueue.isRunning()) 736 break; 737 if (newMessages > 60 || (newMessages > 0 && null == oriMsg)) { 738 newMessages = 0; 739 if (current != null && current.uiUpdate) 740 getSite().getShell().getDisplay().syncExec(new Runnable() { 741 @Override 742 public void run() { 743 if (frameNum.getSelection() == current.frameCount() - 1 || 744 frameNum.getSelection() == current.frameCount() - 2) 745 { 746 viewer.refresh(false); 747 if (actionAutoScroll.isChecked()) 748 viewer.getList().setSelection( 749 viewer.getList().getItemCount() - 1); 750 } 751 frameNum.setMaximum(current.frameCount()); 752 } 753 }); 754 current.uiUpdate = false; 755 756 if (shaderEditorUpdate) 757 this.getSite().getShell().getDisplay().syncExec(new Runnable() { 758 @Override 759 public void run() { 760 shaderEditor.updateUI(); 761 } 762 }); 763 shaderEditorUpdate = false; 764 } 765 if (null == oriMsg) { 766 try { 767 Thread.sleep(1); 768 continue; 769 } catch (InterruptedException e) { 770 showError(e); 771 } 772 } 773 DebugContext debugContext = debugContexts.get(oriMsg.getContextId()); 774 if (debugContext == null) { 775 debugContext = new DebugContext(oriMsg.getContextId()); 776 debugContexts.put(oriMsg.getContextId(), debugContext); 777 } 778 debugContext.processMessage(oriMsg); 779 shaderEditorUpdate |= debugContext.currentContext.serverShader.uiUpdate; 780 debugContext.currentContext.serverShader.uiUpdate = false; 781 if (current == null && debugContext.frameCount() > 0) 782 changeContext(debugContext); 783 newMessages++; 784 } 785 if (running) 786 connectDisconnect(); // error occurred, disconnect 787 } 788 789 /** can be called from non-UI thread */ changeContext(final DebugContext newContext)790 void changeContext(final DebugContext newContext) { 791 getSite().getShell().getDisplay().syncExec(new Runnable() { 792 @Override 793 public void run() { 794 current = newContext; 795 if (current != null) 796 { 797 frameNum.setMaximum(current.frameCount()); 798 if (frameNum.getSelection() >= current.frameCount()) 799 if (current.frameCount() > 0) 800 frameNum.setSelection(current.frameCount() - 1); 801 else 802 frameNum.setSelection(0); 803 viewer.setInput(current.getFrame(frameNum.getSelection())); 804 actContext.setText("Context: 0x" + Integer.toHexString(current.contextId)); 805 } 806 else 807 { 808 frameNum.setMaximum(1); // cannot overlap min 809 frameNum.setSelection(0); 810 viewer.setInput(null); 811 actContext.setText("Context: 0x"); 812 } 813 shaderEditor.updateUI(); 814 getViewSite().getActionBars().getToolBarManager().update(true); 815 } 816 }); 817 } 818 819 @Override widgetSelected(SelectionEvent e)820 public void widgetSelected(SelectionEvent e) { 821 if (e.widget != frameNum) 822 assert false; 823 if (current == null) 824 return; 825 if (frameNum.getSelection() == current.frameCount()) 826 return; // scale maximum cannot overlap minimum 827 Frame frame = current.getFrame(frameNum.getSelection()); 828 viewer.setInput(frame); 829 } 830 831 @Override widgetDefaultSelected(SelectionEvent e)832 public void widgetDefaultSelected(SelectionEvent e) { 833 widgetSelected(e); 834 } 835 } 836