Home | History | Annotate | Download | only in client
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "gpu/command_buffer/client/query_tracker.h"
      6 
      7 #include <GLES2/gl2.h>
      8 #include <GLES2/gl2ext.h>
      9 #include <GLES2/gl2extchromium.h>
     10 
     11 #include "base/atomicops.h"
     12 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
     13 #include "gpu/command_buffer/client/gles2_implementation.h"
     14 #include "gpu/command_buffer/client/mapped_memory.h"
     15 #include "gpu/command_buffer/common/time.h"
     16 
     17 namespace gpu {
     18 namespace gles2 {
     19 
     20 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
     21     : mapped_memory_(manager) {
     22   DCHECK(manager);
     23 }
     24 
     25 QuerySyncManager::~QuerySyncManager() {
     26   while (!buckets_.empty()) {
     27     mapped_memory_->Free(buckets_.front()->syncs);
     28     delete buckets_.front();
     29     buckets_.pop_front();
     30   }
     31 }
     32 
     33 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
     34   DCHECK(info);
     35   if (free_queries_.empty()) {
     36     int32 shm_id;
     37     unsigned int shm_offset;
     38     void* mem = mapped_memory_->Alloc(
     39         kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
     40     if (!mem) {
     41       return false;
     42     }
     43     QuerySync* syncs = static_cast<QuerySync*>(mem);
     44     Bucket* bucket = new Bucket(syncs);
     45     buckets_.push_back(bucket);
     46     for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
     47       free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
     48       ++syncs;
     49       shm_offset += sizeof(*syncs);
     50     }
     51   }
     52   *info = free_queries_.front();
     53   ++(info->bucket->used_query_count);
     54   info->sync->Reset();
     55   free_queries_.pop_front();
     56   return true;
     57 }
     58 
     59 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
     60   DCHECK_GT(info.bucket->used_query_count, 0u);
     61   --(info.bucket->used_query_count);
     62   free_queries_.push_back(info);
     63 }
     64 
     65 void QuerySyncManager::Shrink() {
     66   std::deque<QueryInfo> new_queue;
     67   while (!free_queries_.empty()) {
     68     if (free_queries_.front().bucket->used_query_count)
     69       new_queue.push_back(free_queries_.front());
     70     free_queries_.pop_front();
     71   }
     72   free_queries_.swap(new_queue);
     73 
     74   std::deque<Bucket*> new_buckets;
     75   while (!buckets_.empty()) {
     76     Bucket* bucket = buckets_.front();
     77     if (bucket->used_query_count) {
     78       new_buckets.push_back(bucket);
     79     } else {
     80       mapped_memory_->Free(bucket->syncs);
     81       delete bucket;
     82     }
     83     buckets_.pop_front();
     84   }
     85   buckets_.swap(new_buckets);
     86 }
     87 
     88 QueryTracker::Query::Query(GLuint id, GLenum target,
     89                            const QuerySyncManager::QueryInfo& info)
     90     : id_(id),
     91       target_(target),
     92       info_(info),
     93       state_(kUninitialized),
     94       submit_count_(0),
     95       token_(0),
     96       flush_count_(0),
     97       client_begin_time_us_(0),
     98       result_(0) {
     99     }
    100 
    101 
    102 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
    103   // init memory, inc count
    104   MarkAsActive();
    105 
    106   switch (target()) {
    107     case GL_GET_ERROR_QUERY_CHROMIUM:
    108       // To nothing on begin for error queries.
    109       break;
    110     case GL_LATENCY_QUERY_CHROMIUM:
    111       client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
    112       // tell service about id, shared memory and count
    113       gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
    114       break;
    115     case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
    116     case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
    117     default:
    118       // tell service about id, shared memory and count
    119       gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
    120       break;
    121   }
    122 }
    123 
    124 void QueryTracker::Query::End(GLES2Implementation* gl) {
    125   switch (target()) {
    126     case GL_GET_ERROR_QUERY_CHROMIUM: {
    127       GLenum error = gl->GetClientSideGLError();
    128       if (error == GL_NO_ERROR) {
    129         // There was no error so start the query on the serivce.
    130         // it will end immediately.
    131         gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
    132       } else {
    133         // There's an error on the client, no need to bother the service. just
    134         // set the query as completed and return the error.
    135         if (error != GL_NO_ERROR) {
    136           state_ = kComplete;
    137           result_ = error;
    138           return;
    139         }
    140       }
    141     }
    142   }
    143   flush_count_ = gl->helper()->flush_generation();
    144   gl->helper()->EndQueryEXT(target(), submit_count());
    145   MarkAsPending(gl->helper()->InsertToken());
    146 }
    147 
    148 bool QueryTracker::Query::CheckResultsAvailable(
    149     CommandBufferHelper* helper) {
    150   if (Pending()) {
    151     if (base::subtle::Acquire_Load(&info_.sync->process_count) ==
    152             submit_count_ ||
    153         helper->IsContextLost()) {
    154       switch (target()) {
    155         case GL_COMMANDS_ISSUED_CHROMIUM:
    156           result_ = std::min(info_.sync->result,
    157                              static_cast<uint64>(0xFFFFFFFFL));
    158           break;
    159         case GL_LATENCY_QUERY_CHROMIUM:
    160           DCHECK(info_.sync->result >= client_begin_time_us_);
    161           result_ = std::min(info_.sync->result - client_begin_time_us_,
    162                              static_cast<uint64>(0xFFFFFFFFL));
    163           break;
    164         case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
    165         case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
    166         default:
    167           result_ = info_.sync->result;
    168           break;
    169       }
    170       state_ = kComplete;
    171     } else {
    172       if ((helper->flush_generation() - flush_count_ - 1) >= 0x80000000) {
    173         helper->Flush();
    174       } else {
    175         // Insert no-ops so that eventually the GPU process will see more work.
    176         helper->Noop(1);
    177       }
    178     }
    179   }
    180   return state_ == kComplete;
    181 }
    182 
    183 uint32 QueryTracker::Query::GetResult() const {
    184   DCHECK(state_ == kComplete || state_ == kUninitialized);
    185   return result_;
    186 }
    187 
    188 QueryTracker::QueryTracker(MappedMemoryManager* manager)
    189     : query_sync_manager_(manager) {
    190 }
    191 
    192 QueryTracker::~QueryTracker() {
    193   while (!queries_.empty()) {
    194     delete queries_.begin()->second;
    195     queries_.erase(queries_.begin());
    196   }
    197   while (!removed_queries_.empty()) {
    198     delete removed_queries_.front();
    199     removed_queries_.pop_front();
    200   }
    201 }
    202 
    203 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
    204   DCHECK_NE(0u, id);
    205   FreeCompletedQueries();
    206   QuerySyncManager::QueryInfo info;
    207   if (!query_sync_manager_.Alloc(&info)) {
    208     return NULL;
    209   }
    210   Query* query = new Query(id, target, info);
    211   std::pair<QueryMap::iterator, bool> result =
    212       queries_.insert(std::make_pair(id, query));
    213   DCHECK(result.second);
    214   return query;
    215 }
    216 
    217 QueryTracker::Query* QueryTracker::GetQuery(
    218     GLuint client_id) {
    219   QueryMap::iterator it = queries_.find(client_id);
    220   return it != queries_.end() ? it->second : NULL;
    221 }
    222 
    223 void QueryTracker::RemoveQuery(GLuint client_id) {
    224   QueryMap::iterator it = queries_.find(client_id);
    225   if (it != queries_.end()) {
    226     Query* query = it->second;
    227     // When you delete a query you can't mark its memory as unused until it's
    228     // completed.
    229     // Note: If you don't do this you won't mess up the service but you will
    230     // mess up yourself.
    231     removed_queries_.push_back(query);
    232     queries_.erase(it);
    233     FreeCompletedQueries();
    234   }
    235 }
    236 
    237 void QueryTracker::Shrink() {
    238   FreeCompletedQueries();
    239   query_sync_manager_.Shrink();
    240 }
    241 
    242 void QueryTracker::FreeCompletedQueries() {
    243   QueryList::iterator it = removed_queries_.begin();
    244   while (it != removed_queries_.end()) {
    245     Query* query = *it;
    246     if (query->Pending() &&
    247         base::subtle::Acquire_Load(&query->info_.sync->process_count) !=
    248             query->submit_count()) {
    249       ++it;
    250       continue;
    251     }
    252 
    253     query_sync_manager_.Free(query->info_);
    254     it = removed_queries_.erase(it);
    255     delete query;
    256   }
    257 }
    258 
    259 }  // namespace gles2
    260 }  // namespace gpu
    261